数“真实”二维数组中的值

发布于 2024-11-26 03:02:52 字数 788 浏览 1 评论 0原文

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

Given the following array $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
        )

)

When I run count(array_filter($mm)) I get 3 as result since it is not recursive.

count(array_filter($mm), COUNT_RECURSIVE) also will not do because I actually need to run the array_filter recursively, and then count its result.

So my question is: how do I recursively run array_filter($mm) in this case?
My expected result here would be 4.

Please note that I am not using any callback so I can exclude false, null and empty.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

囚你心 2024-12-03 03:02:52

来自 PHP array_filter 文档

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

From the 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); 
  } 
?>
梦途 2024-12-03 03:02:52

应该可行

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

)

Should work

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

or maybe

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

There are definitely many more possible solutions. If you want to use array_filter() (without callback) remember, that it treats 0 as false too and therefore it will remove any 0-value from the array.

If you are using PHP in a pre-5.3 version, I would use a 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']);
}

Update

Regarding the comment below:

Thx @kc I actually want the method to remove false, 0, empty etc

When this is really only, what you want, the solution is very simple too.
But now I don't know, how to interpret

My expected result here would be 5.

Anyway, its short now :)

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

The resulting array looks like

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

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

)
酸甜透明夹心 2024-12-03 03:02:52

更好的替代方案

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

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.8 秒内完成,并且在启动该函数之前 PHP 分配的内存为 65MB,当函数返回时为 39.35MB!!!
    • array_filter_recursive 上面由 Francois Deschenes 推荐的函数没有机会; 1 秒后 PHP 致命错误:允许的内存大小 134217728 字节耗尽
  2. A 36MB 数组
    • filter_me 函数在 0.4 秒内完成,并且在启动该函数之前 PHP 分配的内存为 36.8MB,当函数返回时为 15MB!
    • array_filter_recursive函数这次在0.6秒内成功,并且之前/之后的内存完全相同

我希望它有所帮助。

A better alternative

One implementation that always worked for me is this one:

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

I notice that someone had created a similar function except that this one presents, in my opinion, few advantages:

  1. you pass an array as reference (not its copy) and thus the algorithm is memory-friendly
  2. no additional calls to array_filter which in reality involves:
    • the use of stack, ie. additional memory
    • some other operations, ie. CPU cycles

Benchmarks

  1. A 64MB array
    • filter_me function finished in 0.8s AND the PHP allocated memory before starting the function was 65MB, when function returned it was 39.35MB !!!
    • array_filter_recursive function recommended above by Francois Deschenes had no chance; after 1s PHP Fatal error: Allowed memory size of 134217728 bytes exhausted
  2. A 36MB array
    • filter_me function finished in 0.4s AND the PHP allocated memory before starting the function was 36.8MB, when function returned it was 15MB !!!
    • array_filter_recursive function succeeded this time in 0.6s and memory before/after was quite the same

I hope it helps.

南街九尾狐 2024-12-03 03:02:52

这个函数有效地应用了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);

这可能会帮助某人

This function effectively applies filter_recursive with a provided callback

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

}

And you'd use it this way:

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

This might help someone

冰魂雪魄 2024-12-03 03:02:52

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


    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

I needed an array filter recursive function that would walk through all nodes (including arrays, so that we have the possibility to discard entire arrays), and so I came up with this:


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

See more examples here: https://github.com/lingtalfi/Bat/blob/master/ArrayTool.md#filterrecursive

寄离 2024-12-03 03:02:52

这应该适用于回调和模式支持以及可选的深度支持。

function array_filter_recursive(array $array, callable $callback = null, int $mode = 0, int $depth = -1): array
{
    foreach ($array as & $value) {
        if ($depth != 0 && is_array($value)) {
            $value = array_filter_recursive($value, $callback, $mode, $depth - 1);
        }
    }

    if ($callback) {
        return array_filter($array, $callback, $mode);
    }

    return array_filter($array);
}

对于嵌套数组,使用 $depth = 0 调用该函数将产生与 array_filter 相同的结果。

This should work for callback and mode support along with an optional support for depth.

function array_filter_recursive(array $array, callable $callback = null, int $mode = 0, int $depth = -1): array
{
    foreach ($array as & $value) {
        if ($depth != 0 && is_array($value)) {
            $value = array_filter_recursive($value, $callback, $mode, $depth - 1);
        }
    }

    if ($callback) {
        return array_filter($array, $callback, $mode);
    }

    return array_filter($array);
}

Calling the function with $depth = 0 for nested arrays, will yield the same result as array_filter.

儭儭莪哋寶赑 2024-12-03 03:02:52
<?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;
?>
<?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;
?>
夏夜暖风 2024-12-03 03:02:52
  1. 不需要递归,因为数组的深度一致为 2 层。
  2. 不需要生成过滤后元素的数组,这样就可以遍历过滤后的数据来统计。只需遍历一次并将每个值转换为布尔值并将其添加到计数总数(添加后将为 0 或 1)。

以下代码片段不调用任何函数(仅调用语言构造 - foreach()),因此效率很高。

代码:(演示)

$truthyCount = 0;
foreach ($array as $row) {
    foreach ($row as $v) {
        $truthyCount += (bool)$v;
    }
}
var_export($truthyCount);

对于函数式方法,将所有真值的映射计数相加。 演示

var_export(
    array_sum(
        array_map(
            fn($row) => count(array_filter($row)),
            $array
        )
    )
);
  1. Recursion is not necessary because the array has a consistent depth of 2 levels.
  2. It is not necessary to generate an array of filtered elements so that you can traverse the filtered data to count it. Just traverse once and cast each value to a boolean and add that (which will be 0 or 1 when added) to the count total.

The following snippet calls no functions (only language constructs -- foreach()) and therefore will be highly efficient.

Code: (Demo)

$truthyCount = 0;
foreach ($array as $row) {
    foreach ($row as $v) {
        $truthyCount += (bool)$v;
    }
}
var_export($truthyCount);

For a functional-style approach, sum the mapped counts of all truthy values. Demo

var_export(
    array_sum(
        array_map(
            fn($row) => count(array_filter($row)),
            $array
        )
    )
);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文