Como posso implodir uma matriz enquanto pulo itens de matriz vazia?

94

Perl's join()ignora (pula) valores de array vazios; PHP implode()não parece.

Suponha que eu tenha uma matriz:

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

rendimentos:

one---four--six

em vez de (IMHO o preferível):

one-four-six

Algum outro built-in com o comportamento que estou procurando? Ou será um jobbie personalizado?

Tom Auger
fonte
2
Você está errado sobre o comportamento de Perl. joinnão pula elementos indefinidos. Na verdade, eles resultam em um aviso. $a[0]="a"; $a[2]="c"; say join "-",@a;exibe Use of uninitialized value within @a in join or stringe a--c. Pode-se usar join '-', grep !defined, ...para pular valores indefinidos. grep !length,fará strings vazias.
ikegami

Respostas:

210

Você pode usar array_filter():

Se nenhum retorno de chamada for fornecido, todas as entradas de entrada iguais a FALSE(consulte convertendo para booleano ) serão removidas.

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

Obviamente, isso não funcionará se você tiver 0(ou qualquer outro valor que avalie como false) em seu array e quiser mantê-lo. Mas então você pode fornecer sua própria função de retorno de chamada.

Felix Kling
fonte
5
Isso significaria isso false, e 0também são jogados fora?
Ben
1
@maz: Sim, mas você sempre pode fornecer seu próprio retorno de chamada. empty, conforme você o usa, também tratará 0e falsecomo false(e removerá) aliás.
Felix Kling
3
+1, mas tem que ser mencionado, que array_filter()por filtros padrão fora de cada false, null, string vazia ( '') e 0.
Tadeck
1
@Tadeck: Sim, basta seguir o link da citação. Ainda mais valores são considerados como false: array vazio 0.0e "0".
Felix Kling
@Felix: Eu sabia - só queria enfatizar isso para pessoas novas em PHP;) De qualquer forma: obrigado
Tadeck de
9

Suponho que você não possa considerá-lo integrado (porque a função está sendo executada com uma função definida pelo usuário), mas você sempre pode usar array_filter .
Algo como:

function rempty ($var)
{
    return !($var == "" || $var == null);
}
$string = implode('-',array_filter($array, 'rempty'));
Ben
fonte
1
Usar emptytem o mesmo efeito que não passar nenhum retorno de chamada. Edit: Você tem que negar o valor de retorno. Caso contrário, apenas elementos vazios serão retornados;) (usar emptycomo você fez antes também estava errado)
Felix Kling
1
Sim, isso é para trás. Mas você me deu a ideia certaimplode('-', array_filter($ary, create_function('$a', 'return $a!="";')));
Tom Auger
3

Como você deve implementar seu filtro depende apenas do que você vê como "vazio".

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
fonte
3

Para remover null, string false, emptymas preservar 0, etc., use func. ' strlen'

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

irá produzir:

//Array ( [3] => 0 [4] => 0 [5] => 1 [6] => 2 [7] => false )
Ali Varli
fonte
1

Com base no que posso encontrar, eu diria que provavelmente não há nenhuma maneira de usar um PHP embutido para isso. Mas você provavelmente poderia fazer algo mais ou menos assim:

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
fonte
1

Experimente isto:

$result = array();

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

implode('-', $result);
Jeremy
fonte
1
$array = ["one", NULL, "two", NULL, "three"];
$string = implode("-", array_diff($array, [NULL]));
echo $string;

Devoluções one-two-three

Ryan Prescott
fonte
-1

array_fileter() parece ser a forma aceita aqui, e provavelmente ainda é a resposta mais robusta tbh.

No entanto, o seguinte também funcionará se você puder garantir que o caractere "cola" ainda não existe nas strings de cada elemento do array (o que seria um dado na maioria das circunstâncias práticas - caso contrário, você não seria capaz de distinguir a cola dos dados reais na matriz):

$array = array('one', '', '', 'four', '', 'six');
$str   = implode('-', $array);
$str   = preg_replace ('/(-)+/', '\1', $str);
carreta
fonte
-3

Experimente isto:

if(isset($array))  $array = implode(",", (array)$array);
user2775080
fonte
Você pode querer usar isset () para prevenir avisos.
user2775080
Não tenho certeza de como isset()ou converter a matriz de entrada como arrayaborda qualquer uma das preocupações do post original?
Tom Auger
1
Esta não é uma solução. Casting to (array) não remove itens vazios do array.
mjwunderlich de