【问题标题】:Recursively remove empty elements and subarrays from a multi-dimensional array从多维数组中递归删除空元素和子数组
【发布时间】:2012-04-11 07:32:51
【问题描述】:

对于 PHP 中从数组中删除空元素这一古老的问题,我似乎找不到简单、直接的解决方案。

我的输入数组可能如下所示:

Array ( [0] => Array ( [Name] => [EmailAddress] => ) ) 

(等等,如果有更多的数据,虽然可能没有......)

如果它看起来像上面那样,我希望它在处理后完全为空

所以print_r($array); 会输出:

Array ( )

如果我运行 $arrayX = array_filter($arrayX);,我仍然会得到 same print_r 输出。然而,我看过的所有地方都表明这是在 PHP5 中删除空数组元素的最简单方法。

我也尝试了$arrayX = array_filter($arrayX,'empty_array');,但出现以下错误:

警告:array_filter() [function.array-filter]:第二个参数“empty_array”应该是一个有效的回调

我做错了什么?

【问题讨论】:

  • array_filter 设置为一维数组。
  • 您能否提供示例输入,以及预期的输出?有几种不同的方式来解释你的问题,“如果它看起来像上面那样,我希望它在处理后完全是空的。” 让我失望,你想要它吗完全消失还是成为一个空数组?
  • 您的新错误是因为empty_array 不是定义的函数。我也想知道你的真正用例是什么......
  • @mickmackusa 正确答案在已接受问题下方的 cmets 中。不知道为什么韦斯利没有把它加入他的答案,但我现在已经添加了。
  • 如果标题改为:Remove empty elements then empty subarrays from a 2d array,你会不会生气? IMO 的这一澄清很重要,因为这样可以更好地针对重复的页面关闭。

标签: php arrays multidimensional-array filtering is-empty


【解决方案1】:

有很多例子可以说明如何做到这一点。你可以试试docs,一个(见第一条评论)。

function array_filter_recursive($array, $callback = null) {
    foreach ($array as $key => & $value) {
        if (is_array($value)) {
            $value = array_filter_recursive($value, $callback);
        }
        else {
            if ( ! is_null($callback)) {
                if ( ! $callback($value)) {
                    unset($array[$key]);
                }
            }
            else {
                if ( ! (bool) $value) {
                    unset($array[$key]);
                }
            }
        }
    }
    unset($value);

    return $array;
}

当然,这个例子实际上并没有使用array_filter,但你明白了。

【讨论】:

  • 这段代码无法取消设置0长度的最深数组,未能跟进清除其所在的三重嵌套结构
【解决方案2】:

尝试使用array_map() 将过滤器应用于$array 中的每个数组:

$array = array_map('array_filter', $array);
$array = array_filter($array);

演示:http://codepad.org/xfXEeApj

【讨论】:

  • 等一下,您是否只想在 所有 项为空时删除整个数组?这不是这样做的。您能否提供示例输入,并提供预期输出?
  • 根据您的问题和 cmets 中的说明,是的,它应该:codepad.org/FdfY5aqj 当所有空项目都被删除时,您最终会得到一个空数组。如果这不是您想要的,请提供一些带有预期输出的示例输入。您是否担心从其他阵列中删除空位的副作用?
  • 它有点工作。它仍然保留空键。所以如果[0][EmailAddress] 为空,[0] 仍然存在。也就是说,它似乎可以满足我的需要,所以谢谢!
  • 嗯,这不是一个空数组,它是一个包含键的数组。我不知道如何描述一个空数组!就像声明为的数组一样:$array = new array();
  • 如果 $array 包含像 $array['number'] = '234'; 这样的简单值,这将不起作用您将在 array_map 中收到警告和错误的结果
【解决方案3】:

按照 jeremyharris 的建议,这就是我需要对其进行更改以使其工作的方式:

function array_filter_recursive($array) {
   foreach ($array as $key => &$value) {
      if (empty($value)) {
         unset($array[$key]);
      }
      else {
         if (is_array($value)) {
            $value = array_filter_recursive($value);
            if (empty($value)) {
               unset($array[$key]);
            }
         }
      }
   }

   return $array;
}

【讨论】:

    【解决方案4】:

    接受的答案并不完全符合 OP 的要求。如果要递归删除所有评估为 false 的值,包括空数组,请使用以下函数:

    function array_trim($input) {
        return is_array($input) ? array_filter($input, 
            function (& $value) { return $value = array_trim($value); }
        ) : $input;
    }
    

    或者您可以根据需要更改退货条件,例如:

    { return !is_array($value) or $value = array_trim($value); }
    

    如果您只想删除空数组。或者您可以将条件更改为仅测试 "" 或 false 或 null 等...

    【讨论】:

    • 请注意,从 PHP7 开始,在 array_filter 中通过引用传递的能力已被删除(很烦人),现在从 PHP8 生成警告。
    【解决方案5】:

    尝试:

    $array = array_filter(array_map('array_filter', $array));
    

    例子:

    $array[0] = array(
       'Name'=>'',
       'EmailAddress'=>'',
    );
    print_r($array);
    
    $array = array_filter(array_map('array_filter', $array));
    
    print_r($array);
    

    输出:

    Array
    (
        [0] => Array
            (
                [Name] => 
                [EmailAddress] => 
            )
    )
    
    Array
    (
    )
    

    【讨论】:

      【解决方案6】:

      array_filter() 默认情况下不区分类型。这意味着将删除任何 zero-ish、false-y、null、空值。我的链接将证明这一点。

      OP 的样本输入数组是二维的。如果数据结构是静态的,则不需要递归。对于任何想从多维数组中过滤零长度值的人,我将提供一个静态 2-dim 方法和一个递归方法。

      静态二维数组: 此代码对第二级元素执行“零安全”过滤,然后删除空子数组:(See this demo to see this method work with different (trickier) array data)

      $array=[
          ['Name'=>'','EmailAddress'=>'']
      ];   
      
      var_export(
          array_filter(  // remove the 2nd level in the event that all subarray elements are removed
              array_map(  // access/iterate 2nd level values
                  function($v){
                      return array_filter($v,'strlen');  // filter out subarray elements with zero-length values
                  },$array  // the input array
              )
          )
      );
      

      这是与单行代码相同的代码:

      var_export(array_filter(array_map(function($v){return array_filter($v,'strlen');},$array)));
      

      输出(最初由 OP 指定):

      array (
      )
      

      *如果您不想删除空子数组,只需删除外部 array_filter() 调用即可。


      未知深度的多维数组的递归方法:当数组中的层数未知时,递归是一种逻辑技术。以下代码将处理每个子数组,删除零长度值和任何空子数组。 Here is a demo of this code with a few sample inputs.

      $array=[
          ['Name'=>'','Array'=>['Keep'=>'Keep','Drop'=>['Drop2'=>'']],'EmailAddress'=>'','Pets'=>0,'Children'=>null],
          ['Name'=>'','EmailAddress'=>'','FavoriteNumber'=>'0']
      ];
      
      function removeEmptyValuesAndSubarrays($array){
         foreach($array as $k=>&$v){
              if(is_array($v)){
                  $v=removeEmptyValuesAndSubarrays($v);  // filter subarray and update array
                  if(!sizeof($v)){ // check array count
                      unset($array[$k]);
                  }
              }elseif(!strlen($v)){  // this will handle (int) type values correctly
                  unset($array[$k]);
              }
         }
         return $array;
      }
      
      var_export(removeEmptyValuesAndSubarrays($array));
      

      输出:

      array (
        0 => 
        array (
          'Array' => 
          array (
            'Keep' => 'Keep',
          ),
          'Pets' => 0,
        ),
        1 => 
        array (
          'FavoriteNumber' => '0',
        ),
      )
      

      如果有人发现一个输入数组破坏了我的递归方法,请将其(以最简单的形式)作为评论发布,我会更新我的答案。

      【讨论】:

      • 感谢递归函数,无需从多维数组中删除零值。
      【解决方案7】:

      当被问到这个问题时,PHP 的最新版本是 5.3.10。到今天为止,它现在是 8.1.1,从那以后发生了很多变化!由于核心功能的变化,一些较早的答案将提供意想不到的结果。因此,我觉得需要一个最新的答案。下面将遍历一个数组,删除任何为空字符串、空数组或 null 的元素(因此 false 和 0 将保留),如果这导致更多的空数组,它也会删除它们。

      function removeEmptyArrayElements( $value ) {
          if( is_array($value) ) {
              $value = array_map('removeEmptyArrayElements', $value);
              $value = array_filter( $value, function($v) {
                  // Change the below to determine which values get removed
                  return !( $v === "" || $v === null || (is_array($v) && empty($v)) );
              } );
          }
          return $value;
      }
      

      要使用它,您只需拨打removeEmptyArrayElements( $array );

      【讨论】:

        【解决方案8】:

        如果在类内部用作辅助方法:

        private function arrayFilterRecursive(array $array): array 
        {
            foreach ($array as $key => &$value) {
                if (empty($value)) {
                    unset($array[$key]);
                } else if (is_array($value)) {
                    $value = self::arrayFilterRecursive($value);
                }
            }
        
            return $array;
        }
        

        【讨论】:

          猜你喜欢
          • 2012-04-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多