【问题标题】:How to run array_filter recursively in a PHP array?如何在 PHP 数组中递归运行 array_filter?
【发布时间】:2011-10-11 08:34:35
【问题描述】:

给定以下数组$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。

【问题讨论】:

  • 你只是想计算有值的数组元素吗?
  • @jrod 是正确的,但不是 0

标签: php recursion count array-filter


【解决方案1】:

应该有效

$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-value。

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

$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、空等

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

我的预期结果是 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
    )

)

【讨论】:

  • Thx @kc 我实际上希望该方法删除 false、0、空等
  • 您的声明“我的预期结果将是5。”那时和删除任何false-评估值count($array) 后仍将不会返回0
  • "... 仍然没有返回 5"。它计算数组的元素,数组是一个元素,因此将被计为1(我只是不希望这条评论愚蠢地“想修正我的错字”..)
  • 非常感谢@kingcrunch -- 您的建议非常有效,非常感谢!
【解决方案2】:

来自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); 
  } 
?>

【讨论】:

  • 这也会删除空和0吗?
  • @torr - 这与array_filter 通常的工作方式相同。如果您查看该函数,它会调用array_filter,除非它的当前值是一个数组,此时它会调用array_filter_recursive 函数。
  • @FrancoisDeschenes: array_filter_recursive 带有回调不能按预期工作,它在递归时给出数组到字符串的转换错误..
  • 不适用于提供的回调。请参阅我的答案以了解工作功能
  • 如果我不传递回调(回调为空),结果也是空的:/不知道为什么
【解决方案3】:
<?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;
?>

【讨论】:

  • 好主意 - 在这种情况下,可以使用 array_filter 代替条件句和 $count++,不是吗?
【解决方案4】:

更好的选择

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

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 周期

基准测试

  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 内成功,之前/之后的内存完全一样

希望对你有帮助。

【讨论】:

  • 但对于特定问题来说,这是一个很好的解决方案;)赞成
【解决方案5】:

此函数通过提供的回调有效地应用 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);

这可能对某人有帮助

【讨论】:

  • 这可能会有所帮助,所以很高兴知道。无论如何,这个问题与如何过滤掉那些“空”记录有关,我的回答集中在为这个问题提供更好的选择。但我同意您的递归过滤器版本具有更广泛的用途。
  • 如果回调返回true,array_filter 不应该保留原始值吗?在这种情况下,您将原始值猛烈抨击为true
  • 销毁输入数组
【解决方案6】:

我需要一个数组过滤递归函数,它可以遍历所有节点(包括数组,这样我们就有可能丢弃整个数组),所以我想出了这个:


    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

【讨论】:

  • 这会改变输入数组
猜你喜欢
  • 2021-10-02
  • 2011-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-20
  • 1970-01-01
  • 2012-07-27
  • 2018-07-06
相关资源
最近更新 更多