简体   繁体   English

从多维数组中递归删除空元素和子数组

[英]Recursively remove empty elements and subarrays from a multi-dimensional array

I can't seem to find a simple, straight-forward solution to the age-old problem of removing empty elements from arrays in PHP.我似乎找不到一个简单直接的解决方案来解决从 PHP 中的 arrays 中删除空元素的古老问题。

My input array may look like this:我的输入数组可能如下所示:

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

(And so on, if there's more data, although there may not be...) (以此类推,如果有更多的数据,虽然可能没有...)

If it looks like the above, I want it to be completely empty after I've processed it.如果它看起来像上面那样,我希望它在我处理完之后完全是空的。

So print_r($array);所以print_r($array); would output: output:

Array ( )

If I run $arrayX = array_filter($arrayX);如果我运行$arrayX = array_filter($arrayX); I still get the same print_r output. Everywhere I've looked suggests this is the simplest way of removing empty array elements in PHP5, however.我仍然得到相同print_r output。然而,我看过的所有地方都表明这是在 PHP5 中删除空数组元素的最简单方法。

I also tried $arrayX = array_filter($arrayX,'empty_array');我也试过$arrayX = array_filter($arrayX,'empty_array'); but I got the following error:但我收到以下错误:

Warning: array_filter() [function.array-filter]: The second argument, 'empty_array', should be a valid callback警告:array_filter() [function.array-filter]:第二个参数“empty_array”应该是一个有效的回调

What am I doing wrong?我究竟做错了什么?

Try using array_map() to apply the filter to every array in $array :尝试使用array_map()将过滤器应用于$array每个$array

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

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

The accepted answer does not do exactly what the OP asked.接受的答案并不完全符合 OP 的要求。 If you want to recursively remove ALL values that evaluate to false including empty arrays then use the following function:如果要递归删除所有评估为 false 的值,包括空数组,请使用以下函数:

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

Or you could change the return condition according to your needs, for example:或者您可以根据需要更改退货条件,例如:

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

If you only want to remove empty arrays.如果您只想删除空数组。 Or you can change the condition to only test for "" or false or null, etc...或者您可以将条件更改为仅测试 "" 或 false 或 null 等...

There are numerous examples of how to do this.有许多示例说明如何执行此操作。 You can try the docs , for one (see the first comment).您可以尝试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;
}

Granted this example doesn't actually use array_filter but you get the point.当然,这个例子实际上并没有使用array_filter但你明白了。

Following up jeremyharris' suggestion, this is how I needed to change it to make it work:遵循 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;
}

Try with:尝试:

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

Example:例子:

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

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

print_r($array);

Output:输出:

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

Array
(
)

array_filter() is not type-sensitive by default.默认情况下, array_filter()不是类型敏感的。 This means that any zero-ish , false-y, null, empty values will be removed.这意味着任何zero-ish 、false-y、null、空值都将被删除。 My links to follow will demonstrate this point.我要遵循的链接将证明这一点。

The OP's sample input array is 2-dimensional. OP 的样本输入数组是二维的。 If the data structure is static then recursion is not necessary.如果数据结构是静态的,则不需要递归。 For anyone who would like to filter the zero-length values from a multi-dimensional array, I'll provide a static 2-dim method and a recursive method.对于想要从多维数组中过滤零长度值的任何人,我将提供静态二维方法和递归方法。

Static 2-dim Array : This code performs a "zero-safe" filter on the 2nd level elements and then removes empty subarrays: ( See this demo to see this method work with different (trickier) array data )静态二维数组:此代码对第 2 级元素执行“零安全”过滤器,然后删除空子数组:( 请参阅此演示以了解此方法适用于不同(更棘手的)数组数据

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

Here is the same code as a one-liner:这是与单行代码相同的代码:

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

Output (as originally specified by the OP):输出(最初由 OP 指定):

array (
)

*if you don't want to remove the empty subarrays, simply remove the outer array_filter() call. *如果您不想删除空子array_filter() ,只需删除外部array_filter()调用。


Recursive method for multi-dimensional arrays of unknown depth : When the number of levels in an array are unknown, recursion is a logical technique.深度未知的多维数组的递归方法:当数组中的级别数未知时,递归是一种逻辑技术。 The following code will process each subarray, removing zero-length values and any empty subarrays as it goes.以下代码将处理每个子数组,同时删除零长度值和任何空子数组。 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));

Output:输出:

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

If anyone discovers an input array that breaks my recursive method, please post it (in its simplest form) as a comment and I'll update my answer.如果有人发现破坏了我的递归方法的输入数组,请将其发布(以最简单的形式)作为评论,我将更新我的答案。

When this question was asked, the latest version of PHP was 5.3.10.问这个问题的时候,PHP的最新版本是5.3.10。 As of today, it is now 8.1.1, and a lot has changed since, Some of the earlier answers will provide unexpected results.截至今天,现在是 8.1.1,此后发生了很多变化,一些较早的答案会提供意想不到的结果。 due to changes in the core functionality, Therefore.由于核心功能的变化,因此。 I feel an up-to-date answer is required, The below will iterate through an array, remove any elements that are either an empty string, empty array, or null (so false and 0 will remain), and if this results in any more empty arrays. it will remove them too.我觉得需要一个最新的答案,下面将遍历一个数组,删除任何空字符串、空数组或 null 的元素(因此 false 和 0 将保留),如果这导致任何更多空 arrays。它也会删除它们。

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

To use it, you simply call removeEmptyArrayElements( $array );要使用它,您只需调用removeEmptyArrayElements( $array );

If used inside class as helper method:如果在 class 内部用作辅助方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM