120

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?

1
  • 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. Commented May 12, 2011 at 23:01

10 Answers 10

255

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.

Sign up to request clarification or add additional context in comments.

6 Comments

Would that mean that false, and 0 are also thrown out?
@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.
+1, but it has to be mentioned, that array_filter() by default filters off every false, null, empty string ('') and 0.
@Tadeck: Yes, just follow the link in the quote. Even more values are considered as false: empty array, 0.0 and "0".
@Felix: I knew it - just wanted to stress it for people new in PHP ;) Anyway: thank you
|
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'));

2 Comments

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)
Yeah, that's backward. But you gave me the right idea implode('-', array_filter($ary, create_function('$a', 'return $a!="";')));
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 )

Comments

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"));
} 

Comments

2
$array = ["one", NULL, "two", NULL, "three"];
$string = implode("-", array_diff($array, [NULL]));
echo $string;

Returns one-two-three

Comments

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;
}

Comments

1

Try this:

$result = array();

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

implode('-', $result);

Comments

0

Not a direct answer, but just a general reminder that you don't have to rely on a separate named function —— you can do this with an inline anonymous function such as:

$imploded = implode("+", array_filter($array, function($chunk) {
        return (trim($chunk)!="");
    }));

2 Comments

The asked question doesn't present any problems with trimmable whitespaces. The asked question doesn't want the values to be imploded with plus symbols. Are you answering the asked question?
The use of “trim” above is testing for the emptiness of a given array item… which is exactly what the OP was wanting to target in order to omit it from the resulting implosion result. You’re right, he didn’t want to use a “+” to concatenate thing, but a person implementing the “implode” function would know they could use whatever string they want there. Point of my post was to highlight the ability to define the function inline whereas all other answers seemed to break it out as an entirely separate callback… high might be overkill and unnecessary.
-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);

Comments

-3

Try this:

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

3 Comments

You might want to use isset() to prevent warnings.
I'm not sure how isset() or casting the input array as array addresses any of the concerns of the original post?
This is not a solution. Casting to (array) does not remove empty items from the array.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.