递归地从多维数组中移除空元素和子数组。

26

我似乎找不到一个简单明了的解决方案来从PHP数组中删除空元素。

我的输入数组可能是这样的:

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

如果还有更多的数据,就像上面的一样,虽然可能没有......

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

因此print_r($array);将输出:

Array ( )
如果我运行 $arrayX = array_filter($arrayX);,我仍然会得到相同的print_r输出。无论在哪里查看,都建议这是在PHP5中删除空数组元素的最简单方法。
我还尝试过$arrayX = array_filter($arrayX,'empty_array');,但我得到了以下错误:

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

我做错了什么?

2
你的新错误是因为empty_array不是一个已定义的函数。我也想知道你在这里的真正用例是什么... - Wesley Murch
这不是破坏性的恶意评论。我花了相当多的时间分析答案并编写自己的方法,以便未来的读者不必浪费时间尝试不同的方法。请参见此演示以比较其他志愿者的答案:http://sandbox.onlinephpfunctions.com/code/be9de9f471997331f248e29282dbd2bc5310777d - mickmackusa
1
@mickmackusa 正确答案在被接受的问题下面的评论中。不确定为什么Wesley没有将其纳入他的答案,但我现在已经添加了它。 - Chuck Le Butt
@mickmackusa 这是您的代码和被接受的答案:http://sandbox.onlinephpfunctions.com/code/038c0f684908d595029df410739599e4b0b2cc51 - Chuck Le Butt
1
如果标题改为“从二维数组中删除空元素和空子数组”,你会感到不满吗?在我看来,这个澄清非常重要,因为可以更好地针对重复页面关闭。 - mickmackusa
显示剩余4条评论
8个回答

54

1
等等,你是想只有当所有项目都为空时才删除整个数组吗?这不是这个程序的作用。你能给出一个带有预期输出的示例输入吗? - Wesley Murch
对我很有效!谢谢! - Sam
1
如果 $array 包含一个简单的值,比如 $array['number'] = '234',那么这个方法就不起作用了。你会在 array_map 中得到一个警告,并且得到错误的结果。 - Pablo Pazos
@PabloPazos 是正确的,第一行会将所有非数组值设置为 null,因为它生成了警告 array_filter() expects parameter 1 to be array, string given in...,然后第二行将删除它们,所以如果您有这样一个数组:['element1', 'element2', ['subelement1', 'subelement2']],那么它将变成这样:[['subelement1', 'subelement2']],这并不理想。 - Smithee
@Smithee 解释得很好,这就是我为什么给这个答案点了踩的原因。 - Pablo Pazos
显示剩余4条评论

6

有很多关于如何做到这一点的例子。您可以尝试文档中的一个(参见第一个评论)。

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的最深层数组,并且未能跟进并清除其所在的三重嵌套结构。 - CodedMonkey

5

被接受的答案并没有完全满足提问者的要求。如果你想要递归地删除所有等同于 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中会生成警告。 - Smithee

5

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

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
(
)

4

array_filter() 默认情况下不区分类型。这意味着任何零值、false值、null值和空值都将被删除。以下链接将证明这一点。

OP 的示例输入数组是二维的。如果数据结构是静态的,则不需要递归。如果有人想从多维数组中过滤掉零长度的值,则我将提供一个静态的二维方法和一个递归方法。

静态二维数组: 这段代码对第二层元素执行“零安全”过滤,然后删除空子数组: (查看此演示以查看此方法如何处理不同(更棘手)的数组数据)

$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)));

输出(如原始规定):

array (
)

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


多维未知深度数组的递归方法: 当数组中的级数未知时,递归是一种合理的技术。以下代码将处理每个子数组,并在处理过程中删除零长度值和任何空的子数组。这里有一个带有几个示例输入的代码演示。

$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',
  ),
)

如果有人发现一个会导致我的递归方法失效的输入数组,请在评论中以最简单的形式发布,我会更新我的回答。

1
感谢您提供递归函数,而无需从多维数组中删除零值。 - Rahul

2
当这个问题被提出时,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);

对我来说运行正常 - amir22

1

如果作为助手方法在类内使用:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接