如何在PHP数组中递归运行array_filter?

时间:2011-07-22 20:17:28

标签: php recursion count array-filter

给出以下数组$mm

Array
(
    [147] => Array
        (
            [pts_m] => 
            [pts_mreg] => 1
            [pts_cg] => 1
        )    
    [158] => Array
        (
            [pts_m] => 
            [pts_mreg] => 
            [pts_cg] => 0
        )

    [159] => Array
        (
            [pts_m] => 
            [pts_mreg] => 1
            [pts_cg] => 1
        )

)

当我运行count(array_filter($mm))时,我得到3因为它不是递归的。

count(array_filter($mm), COUNT_RECURSIVE)也不会这样做,因为我实际上需要递归地运行array_filter,然后计算其结果。

所以我的问题是:在这种情况下如何以递归方式运行array_filter($mm)? 我的预期结果是4

请注意,我没有使用任何回调,因此我可以排除false,null和empty。

6 个答案:

答案 0 :(得分:25)

来自PHP array_filter documentation

//This function filters an array and remove all null values recursively. 

<?php 
  function array_filter_recursive($input) 
  { 
    foreach ($input as &$value) 
    { 
      if (is_array($value)) 
      { 
        $value = array_filter_recursive($value); 
      } 
    } 

    return array_filter($input); 
  } 
?> 

//Or with callback parameter (not tested) : 

<?php 
  function array_filter_recursive($input, $callback = null) 
  { 
    foreach ($input as &$value) 
    { 
      if (is_array($value)) 
      { 
        $value = array_filter_recursive($value, $callback); 
      } 
    } 

    return array_filter($input, $callback); 
  } 
?>

答案 1 :(得分:8)

应该工作

$count = array_sum(array_map(function ($item) {
  return ((int) !is_null($item['pts_m'])
       + ((int) !is_null($item['pts_mreg'])
       + ((int) !is_null($item['pts_cg']);
}, $array);

或者

$count = array_sum(array_map(function ($item) {
  return array_sum(array_map('is_int', $item));
}, $array);

肯定有更多可能的解决方案。如果您想使用array_filter()(没有回调),请将0视为false,因此它将删除任何0 - 数组中的值。

如果您在5.3之前的版本中使用PHP,我会使用foreach - 循环

$count = 0;
foreach ($array as $item) {
  $count += ((int) !is_null($item['pts_m'])
          + ((int) !is_null($item['pts_mreg'])
          + ((int) !is_null($item['pts_cg']);
}

更新

关于以下评论:

  

Thx @kc我实际上希望该方法删除false,0,empty等

当这真的只是你想要的时候,解决方案也很简单。 但现在我不知道,如何解释

  

我的预期结果是5。

无论如何,它现在很短暂了:)。

$result = array_map('array_filter', $array);
$count = array_map('count', $result);
$countSum = array_sum($count);

结果数组看起来像

Array
(
[147] => Array
    (
        [pts_mreg] => 1
        [pts_cg] => 1
    )    
[158] => Array
    (
    )

[159] => Array
    (
        [pts_mreg] => 1
        [pts_cg] => 1
    )

)

答案 2 :(得分:5)

更好的选择

总是对我有用的一个实现就是这个:

function filter_me(&$array) {
    foreach ( $array as $key => $item ) {
        is_array ( $item ) && $array [$key] = filter_me ( $item );
        if (empty ( $array [$key] ))
            unset ( $array [$key] );
    }
    return $array;
}

我注意到有人创造了类似的功能,但在我看来,这个功能没有什么优势:

  1. 你传递一个数组作为参考(而不是它的副本),因此该算法是对内存友好的
  2. 没有对array_filter的额外调用,实际上涉及:
    • 使用堆栈,即。额外的记忆
    • 其他一些操作,即。 CPU周期
  3. <强>基准

    1. 64MB阵列
      • filter_me 函数在0.8s内完成,启动函数前PHP分配的内存为65MB,当函数返回时为39.35MB !!!
      • Francois Deschenes上面推荐的
      • array_filter_recursive 函数没有机会; 1s后PHP致命错误:允许的内存大小为134217728字节耗尽
    2. 36MB阵列
      • filter_me 函数在0.4s内完成,启动函数前PHP分配的内存为36.8MB,当函数返回时为15MB !!!
      • array_filter_recursive 函数这次以0.6s成功,而且之前/之后的内存完全相同
    3. 我希望它有所帮助。

答案 3 :(得分:2)

此函数有效地将filter_recursive应用于提供的回调

class Arr {

    public static function filter_recursive($array, $callback = NULL)
    {
        foreach ($array as $index => $value)
        {
            if (is_array($value))
            {
                $array[$index] = Arr::filter_recursive($value, $callback);
            }
            else
            {
                $array[$index] = call_user_func($callback, $value);
            }

            if ( ! $array[$index])
            {
                unset($array[$index]);
            }
        }

        return $array;
    }

}

你可以这样使用它:

Arr::filter_recursive($my_array, $my_callback);

这可能有助于某人

答案 4 :(得分:0)

<?php

$mm = array
(
    147 => array
        (
            "pts_m" => "",
            "pts_mreg" => 1,
            "pts_cg" => 1
        ) ,
    158 => array
        (
            "pts_m" => null ,
            "pts_mreg" => null,
            "pts_cg" => 0
        ),

    159 => array
        (
            "pts_m" => "",
            "pts_mreg" => 1,
            "pts_cg" => 1
        )

);

$count = 0;
foreach ($mm as $m) {
    foreach ($m as $value) {
        if($value !== false && $value !== "" && $value !== null) {
            $count++;
        }
    }
}
echo $count;
?>

答案 5 :(得分:0)

我需要一个遍历所有节点(包括数组,以便我们有可能丢弃整个数组)的数组过滤器递归函数,因此我想到了:


    public static function filterRecursive(array $array, callable $callback): array
    {
        foreach ($array as $k => $v) {
            $res = call_user_func($callback, $v);
            if (false === $res) {
                unset($array[$k]);
            } else {
                if (is_array($v)) {
                    $array[$k] = self::filterRecursive($v, $callback);
                }
            }
        }

        return $array;
    }

在此处查看更多示例:https://github.com/lingtalfi/Bat/blob/master/ArrayTool.md#filterrecursive