给定以下数组$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和空。
来自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);
}
?>
应该工作
$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']);
}
更新
关于下面的注释:
谢谢@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
)
)
一个更好的选择
一个对我来说一直有效的实现是这样的:
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;
}
我注意到有人已经创建了一个类似的函数,只是在我看来,这个函数没有什么优点:
- 你传递一个数组作为引用(而不是它的副本),因此算法是内存友好的
- 没有对array_filter的额外调用,这实际上涉及:
- 栈的使用,即。额外的内存
- 一些其他操作,例如:CPU周期
- 64MB的数组
- filter_me函数在0.8s内完成,函数启动前PHP分配的内存为65MB,函数返回时为39.35MB !! Francois Deschenes推荐的
- array_filter_recursive函数没有机会;1秒后PHP致命错误:允许的内存大小为134217728字节耗尽
- 36MB的数组
- filter_me函数在0.4s内完成,函数启动前PHP分配的内存为36.8MB,函数返回时为15MB !!
- array_filter_recursive函数这次在0.6s内成功,前后的内存完全相同
该函数通过提供的回调有效地应用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);
这可能对某人有帮助
我需要一个数组过滤器递归函数,它可以遍历所有节点(包括数组,这样我们就有可能放弃整个数组),所以我想到了这个:
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
这应该可以支持回调和模式以及可选的深度支持。
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
相同的结果。
我觉得这是一个XY问题。
- 递归是不必要的,因为数组的深度一致为2层。
- 没有必要生成一个经过过滤的元素数组,以便遍历经过过滤的数据来对其进行计数。只要遍历一次,每当遇到真值时,就给count变量加1。
下面的代码片段不调用函数(只调用语言结构——foreach()
),因此效率很高。
代码(演示):
$truthyCount = 0;
foreach ($array as $row) {
foreach ($row as $v) {
$truthyCount += (bool) $v;
}
}
var_export($truthyCount);
<?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;
?>