116

Perl's join() ignores (skips) empty array values; PHP's implode() does not appear to.

Suppose I have an array:

$array = array('one', '', '', 'four', '', 'six');
implode('-', $array);

yields:

one---four--six

instead of (IMHO the preferable):

one-four-six

Any other built-ins with the behaviour I'm looking for? Or is it going to be a custom jobbie?

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Tom Auger
  • 19,421
  • 22
  • 81
  • 104
  • 2
    You're wrong about Perl's behaviour. `join` doesn't skip undefined elements. In fact, they result in a warning. `$a[0]="a"; $a[2]="c"; say join "-",@a;` displays `Use of uninitialized value within @a in join or string` and `a--c`. One can use `join '-', grep !defined, ...` to skip undefined values. `grep !length,` will do empty strings. – ikegami May 12 '11 at 23:01

9 Answers9

247

You can use array_filter():

If no callback is supplied, all entries of input equal to FALSE (see converting to boolean) will be removed.

implode('-', array_filter($array));

Obviously this will not work if you have 0 (or any other value that evaluates to false) in your array and you want to keep it. But then you can provide your own callback function.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 6
    Would that mean that `false`, and `0` are also thrown out? – Jess May 12 '11 at 22:54
  • 1
    @maz: Yes, but you can always provide your own callback. `empty`, as you use it, will also treat `0` and `false` as `false` (and remove it) btw. – Felix Kling May 12 '11 at 22:55
  • 6
    +1, but it has to be mentioned, that `array_filter()` by default filters off every `false`, `null`, empty string ('') and `0`. – Tadeck May 12 '11 at 22:55
  • 1
    @Tadeck: Yes, just follow the link in the quote. Even more values are considered as `false`: empty array, `0.0` and `"0"`. – Felix Kling May 12 '11 at 22:58
  • @Felix: I knew it - just wanted to stress it for people new in PHP ;) Anyway: thank you – Tadeck May 12 '11 at 23:05
  • Nice trick - didn't know array_filter can work without callback :) – Andis Mar 21 '22 at 15:52
9

I suppose you can't consider it built in (because the function is running with a user defined function), but you could always use array_filter.
Something like:

function rempty ($var)
{
    return !($var == "" || $var == null);
}
$string = implode('-',array_filter($array, 'rempty'));
Jess
  • 8,628
  • 6
  • 49
  • 67
  • 1
    Using `empty` has the same effect as passing no callback at all. *Edit: You have to negate the return value. Otherwise only empty elements will be returned ;) (actually using `empty` as you did before was also wrong)* – Felix Kling May 12 '11 at 23:03
  • 1
    Yeah, that's backward. But you gave me the right idea `implode('-', array_filter($ary, create_function('$a', 'return $a!="";')));` – Tom Auger May 12 '11 at 23:12
8

To remove null, false, empty string but preserve 0, etc. use func. 'strlen'

$arr = [null, false, "", 0, "0", "1", "2", "false"];
print_r(array_filter($arr, 'strlen'));

will output:

//Array ( [3] => 0 [4] => 0 [5] => 1 [6] => 2 [7] => false )
ElasticCode
  • 7,311
  • 2
  • 34
  • 45
Ali Varli
  • 189
  • 1
  • 6
3

How you should implement you filter only depends on what you see as "empty".

function my_filter($item)
{
    return !empty($item); // Will discard 0, 0.0, '0', '', NULL, array() of FALSE
    // Or...
    return !is_null($item); // Will only discard NULL
    // or...
    return $item != "" && $item !== NULL; // Discards empty strings and NULL
    // or... whatever test you feel like doing
}

function my_join($array)
{
    return implode('-',array_filter($array,"my_filter"));
} 
Thomas Hupkens
  • 1,570
  • 10
  • 16
2
$array = ["one", NULL, "two", NULL, "three"];
$string = implode("-", array_diff($array, [NULL]));
echo $string;

Returns one-two-three

1

Based on what I can find, I'd say chances are, there isn't really any way to use a PHP built in for that. But you could probably do something along the lines of this:

function implode_skip_empty($glue,$arr) {
      $ret = "";
      $len = sizeof($arr);
      for($i=0;$i<$len;$i++) {
          $val = $arr[$i];    
          if($val == "") {
              continue;
          } else {
            $ret .= $arr.($i+1==$len)?"":$glue;
          }
      }
      return $ret;
}
ozzmotik
  • 377
  • 1
  • 3
  • 12
1

Try this:

$result = array();

foreach($array as $row) { 
   if ($row != '') {
   array_push($result, $row); 
   }
}

implode('-', $result);
Jeremy
  • 1,141
  • 5
  • 20
  • 31
-1

array_fileter() seems to be the accepted way here, and is probably still the most robust answer tbh.

However, the following will also work if you can guarantee that the "glue" character doesn't already exist in the strings of each array element (which would be a given under most practical circumstances -- otherwise you wouldn't be able to distinguish the glue from the actual data in the array):

$array = array('one', '', '', 'four', '', 'six');
$str   = implode('-', $array);
$str   = preg_replace ('/(-)+/', '\1', $str);
cartbeforehorse
  • 3,045
  • 1
  • 34
  • 49
-3

Try this:

if(isset($array))  $array = implode(",", (array)$array);