PHP按ac_no分组二维数组 累加后续金额绝对值至组内前置项
按ac_no分组累加金额实现方案
需求规则
使用array_key_exists()可完成重复键检测与基础值求和,但本次需求不需要将同组所有值合并为单个结果,核心规则为:
遍历数组元素按ac_no字段分组,每遇到相同ac_no的新记录时,将该条记录的amount取绝对值,累加到同组内所有已经存在的前置金额项上,最终每个原记录位置都保留对应的累加后金额。
示例输入
$array = [ ['ac_no' => 100001, 'amount' => 0.00], ['ac_no' => 100001, 'amount' => 51255.11], ['ac_no' => 100001, 'amount' => -500.00], ['ac_no' => 100001, 'amount' => -621.05], ['ac_no' => 100002, 'amount' => .00], ['ac_no' => 100003, 'amount' => .00], ['ac_no' => 100004, 'amount' => 20714.00], ['ac_no' => 100004, 'amount' => 0.00] ];
预期结果(以ac_no=100001分组为例)
每个元素值为对应位置及之后所有amount绝对值的累加和:
[ 52376.05, // 0.00 + 51255.11 + abs(-500.00) + abs(-621.05) 52376.05, // 51255.11 + abs(-500.00) + abs(-621.05) 1121.05, // abs(-500.00) + abs(-621.05) 注:示例标注1120.94为浮点数计算精度误差 621.05 // abs(-621.05) ]
原有代码问题
原有尝试代码无法实现需求,核心问题有三点:
- 每个
ac_no分组仅保留单条记录,没有保留同组下所有原记录的位置 - 错误对
ac_no字段做数值累加,该字段为分组标识不需要参与计算 - 没有实现新条目金额回写同组所有前置条目的逻辑
foreach ($nameAndCode as $key => $vals) { if (array_key_exists($vals['ac_no'], $res)) { $amt = abs($vals['amount']); $res[$vals['ac_no']]['ac_no'] += $vals['ac_no']; $res[$vals['ac_no']]['amount'] += $amt; } else { $res[$vals['ac_no']] = $vals; } }
正确实现代码
采用「先分组、后倒序计算后缀和」的逻辑实现,和需求规则完全等价,性能更高:
$res = []; $groups = []; // 第一遍遍历:按ac_no分组,记录每组元素的原始索引和金额 foreach ($array as $idx => $item) { $acNo = $item['ac_no']; if (!array_key_exists($acNo, $groups)) { $groups[$acNo] = []; } $groups[$acNo][] = [ 'origin_idx' => $idx, 'amount' => $item['amount'] ]; } // 第二遍遍历:逐组倒序计算累加和 foreach ($groups as $acNo => $groupItems) { $runningTotal = 0; // 从分组最后一个元素向前遍历 for ($i = count($groupItems) - 1; $i >= 0; $i--) { $current = $groupItems[$i]; $runningTotal += abs($current['amount']); // 将计算结果填回对应原始索引位置 $res[$current['origin_idx']] = [ 'ac_no' => $acNo, 'amount' => $runningTotal ]; } } // 按原数组顺序重排结果 ksort($res);
逻辑说明
- 第一遍遍历仅做分组归集,不做金额计算,避免遍历过程中反复修改前置项的冗余操作
- 倒序计算后缀和的逻辑,和需求中「新条目金额累加到所有前置项」的规则完全一致:越靠前的元素,累加的后续条目越多
- 最终输出保留原数组的键值结构和顺序,不会修改
ac_no字段值
内容的提问来源于stack exchange,提问作者fagbemi ayodele
相关产品推荐
相关产品推荐

