过滤递归数组并仅删除 NULL 值

Posted

技术标签:

【中文标题】过滤递归数组并仅删除 NULL 值【英文标题】:Filter recursive array and only remove NULL value 【发布时间】:2017-09-13 22:52:25 【问题描述】:

我想从递归数组中删除所有 null 或空白值,但不是 false 和 0 值。

function isNotNull($val) 
    if(is_array($val)) 
        $ret = array_filter($val, 'isNotNull');
        return $ret;
     else 
        return (!is_null($val) && $val !== '');
   


$arr = array_filter($arr, 'isNotNull');

输入:

$arr = array(
"stringKey" => "Abc",
"boolKey" => false,
"zeroKey" => 0,
"blankKey" => '',
"newArr" => array(
    "stringKey2"=>"Abc2", 
    "boolKey2"=>false, 
    "zeroKey2" => 0, 
    "blankKey2"=>"", 
    "blankArr" => array()
    )
);

这给出输出:

Array
(
    [stringKey] => Abc
    [boolKey] => 
    [zeroKey] => 0
    [newArr] => Array
        (
            [stringKey2] => Abc2
            [boolKey2] => 
            [zeroKey2] => 0
            [blankKey2] => 
            [blankArr] => Array
                (
                )
        )
)

但我想大声输出:

 Array
(
    [stringKey] => Abc
    [boolKey] => 
    [zeroKey] => 0
    [newArr] => Array
        (
            [stringKey2] => Abc2
            [boolKey2] => 
            [zeroKey2] => 0
        )
)

我使用带有回调函数的array_filter,但它只过滤简单数组而不是多维数组。我不想使用循环。

【问题讨论】:

你从回调函数内部调用回调函数。为什么? @diavolic bcz 我想过滤多维数组 您使用 is_null() 函数,但它仅在您将变量设置为 NULL 时才有效。要获得所需的结果,请使用 empty() empty() 删除 false 或 0 值,但我不想删除 0 或 false 值 【参考方案1】:

您可以将array_maparray_filter 组合在一个递归调用函数中。像这样的东西可能对你有用。

function filterNotNull($array) 
    $array = array_map(function($item) 
        return is_array($item) ? filterNotNull($item) : $item;
    , $array);
    return array_filter($array, function($item) 
        return $item !== "" && $item !== null && (!is_array($item) || count($item) > 0);
    );

【讨论】:

【参考方案2】:

不需要自己重新发明递归。你可以使用RecursiveCallbackFilterIterator:

$iterator = new RecursiveIteratorIterator(
    new RecursiveCallbackFilterIterator(
        new RecursiveArrayIterator($arr),
        function ($value) 
            return $value !== null && $value !== '';
        
    )
);

$result = iterator_to_array($iterator);

这里是working demo。

您应该尽可能多地使用来自 Standard PHP Library (SPL) 的内容。

更新: 正如 cmets 中所述,带有迭代器的解决方案实际上并不适合此目的。

array_walk_recursive函数的cmets中可以找到walk_recursive_remove函数的实现:

function walk_recursive_remove (array $array, callable $callback)  
    foreach ($array as $k => $v)  
        if (is_array($v))  
            $array[$k] = walk_recursive_remove($v, $callback); 
         else  
            if ($callback($v, $k))  
                unset($array[$k]); 
             
         
     

    return $array; 
 

这个递归函数的通用版本采用回调形式的标准。有了这个功能,你可以像这样删除空元素:

$result = walk_recursive_remove($arr, function ($value) 
    return $value === null || $value === '';
);

这里是working demo。

【讨论】:

@Philipp,是的,我的错。我已经更新了我的答案。感谢您指出这一点。 不错的解决方案。有没有办法让它删除具有特定键而不是值的子数组? @DønerM.,谢谢。 $key 作为第二个参数传递给回调。所以你可以用它来匹配标准。【参考方案3】:

这里您需要过滤empty string 的数组。在下面的代码中,您可以不添加任何检查来递归过滤它。希望一切顺利。

Try this code snippet here

<?php

ini_set('display_errors', 1);
//Using more complexed sample array for filter it.
$arr = array(
    "stringKey" => "Abc",
    "boolKey" => false,
    "zeroKey" => 0,
    "blankKey" => '',
    "newArr" => array(
        "stringKey2" => "Abc2",
        "boolKey2" => false,
        "zeroKey2" => 0,
        "blankKey2" => "",
        "blankArr" => array(
            "blankString"=>"",
            "zeroKey"=>0,
            "blankArr3"=>array()
        )
    )
);

$result=recursiveFilter($arr);
print_r($result);


function recursiveFilter($value)

    foreach ($value as $key => $value1)
    
        if ($value1 === "")  unset($value[$key]);//you can add no. of conditions here.
        else if (is_array($value1)) $value[$key] = recursiveFilter($value1);
    
    return $value;

输出:

Array
(
    [stringKey] => Abc
    [boolKey] => 
    [zeroKey] => 0
    [newArr] => Array
        (
            [stringKey2] => Abc2
            [boolKey2] => 
            [zeroKey2] => 0
            [blankArr] => Array
                (
                    [zeroKey] => 0
                    [blankArr3] => Array
                        (
                        )

                )

        )

)

【讨论】:

以上是关于过滤递归数组并仅删除 NULL 值的主要内容,如果未能解决你的问题,请参考以下文章

php数组的重复值如何过滤掉

JavaScript 通过数组过滤并仅基于一个值的匹配返回

链表 | 递归删除不带头结点链表所有x元素

如何删除多维数组中的唯一元素?

递归过滤对象数组

如何递归地将目录复制到另一个目录并仅替换未更改的文件?