[英]A recursive walk-through over a 10000 element array in PHP: Maximum function nesting level reached
我有一个 2 元素 arrays 的排序数组,如下所示:
array(
array('id' => 1734, 'count' => 14),
array('id' => 1734, 'count' => 7),
array('id' => 9374, 'count' => 5),
array('id' => 9374, 'count' => 253)
);
该数组按内部 arrays 的“id”字段排序。 目标是将其减少到以下内容:
array(
array('id' => 1734, 'count' => 21),
array('id' => 9374', 'count' => 258)
);
即对每个唯一的“id”的“count”元素进行聚合/求和。
我通过 function myfunc(array $arr){...} 执行 array_shift($arr) 然后调用 myfunc($arr) 中的数组 go。 它还对递归的基本情况(一个空数组)进行了适当的检查,并且应该在此时终止。
问题是我有成千上万的内部 arrays 和 PHP 抛出“PHP 致命错误:未捕获的错误:最大 ZC1C425268E68385D1AB5074C17A94F14'Z 嵌套级别达到。”
在仔细检查代码并运行调试 session 后,我看到 $arr 确实在每次调用中减小了它的大小,所以我认为问题只在于最大的 function 嵌套设置。 但是,对我来说,将此设置更改为 100 万似乎是不切实际的。 那么,我们还有什么其他的解决方案呢?
除非它是一个要求,否则递归可能不是 go 的方式。
<?php
$arr = array(
array('id' => 1734, 'count' => 14),
array('id' => 1734, 'count' => 7),
array('id' => 9374, 'count' => 5),
array('id' => 9374, 'count' => 253)
);
$agg = array();
foreach ($arr as $v){
if (isset($agg[$v['id']])){$agg[$v['id']] += $v['count'];}
else {$agg[$v['id']] = $v['count'];}
}
无论如何,您必须至少查看$arr
中的每个元素一次,并且 hash 查找(又名isset($v['id'])
)是 O(1) 操作。 正如奥利弗的解决方案所指出的那样,您实际上不需要检查密钥是否存在,您可以盲目地+=
对该密钥。
使用迭代算法而不是递归算法:
// add up the count for each id
$counts = [];
foreach ($arr as $row) {
$counts[$row['id']] += $row['count'];
}
// format the counts as an array of records
$answer = [];
foreach ($counts as $id => $count) {
$answer[] = ['id' => $id, 'count' => $count];
}
请注意,递归算法在用于大型数据集时往往会超出堆栈的容量,除非它们以使用尾调用优化的方式编写,并且假设语言支持尾调用优化,PHP 目前不支持。
此解决方案基于您的数组称为$arr
:
$new_arr = [];
foreach($arr as $item) {
$key = $item['id'];
$new_arr[$key]['id'] = $item['id'];
isset($new_arr[$key]['count']) ?
$new_arr[$key]['count'] += $item['count'] :
$new_arr[$key]['count'] = $item['count'];
}
//This code would output your expected result. Without array_values you will
//get the key values equals to your values of id
echo '<pre>';
print_r(array_values($new_arr));
echo '</pre>';
只使用一个读取循环并同时添加和创建新数组很简单。 最后使用array_values()重新创建父数组键的顺序。
$arr = [
['id' => 1734, 'count' => 14],
['id' => 9388, 'count' => 25],
['id' => 1734, 'count' => 7],
['id' => 9374, 'count' => 5],
['id' => 9374, 'count' => 253]
];
$counts = [];
foreach($arr as $row)
{
if(isset($counts[$row['id']])){
$sum = $counts[$row['id']]["count"] + $row['count']];
$counts[$row['id']] = [
"id" => $row['id'],
"count" => $sum
];
}else{
$counts[$row['id']] = [
"id" => $row['id'],
"count" => $row['count']
];
}
}
var_dump(array_values($counts));
我希望这个提示会有所帮助。 代码经过测试,成功,代码不错!
谢谢你的回答。 我显然没有提到的一件事是我希望解决方案具有功能性。
我等效地(就结果而言)重写了算法以使用 array_reduce()。 这使我能够保持功能风格并完成工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.