问题定义与数据准备
按 color 分组并累加指定数值字段(如 amount),本质是将「同色多行」折叠为「一色一行」。假设数据结构如下:
$rows = [
['color' => 'red', 'amount' => 10],
['color' => 'blue', 'amount' => 5],
['color' => 'red', 'amount' => 20],
['color' => 'green', 'amount' => 8],
['color' => 'blue', 'amount' => 15],
];
目标输出:red => 30、blue => 20、green => 8。
方案一:foreach 循环(最通用)
$result = [];
foreach ($rows as $row) {
$color = $row['color'];
$result[$color] = ($result[$color] ?? 0) + $row['amount'];
}
- 单次遍历,时间复杂度 O(n),无需额外函数调用开销。
- 空值合并运算符
??避免isset判断,代码更紧凑。 - 可扩展性强:需要同时累加多个字段时,直接在同一循环内追加即可。
方案二:array_reduce(函数式风格)
$result = array_reduce($rows, function ($carry, $row) {
$carry[$row['color']] = ($carry[$row['color']] ?? 0) + $row['amount'];
return $carry;
}, []);
- 语义清晰,适合偏好函数式写法的团队。
- 内部仍是逐元素回调,回调调用带来额外开销,数据量大时通常慢于裸
foreach。 - 调试时堆栈更深,排查成本略高。
方案三:SQL GROUP BY(数据源头聚合)
SELECT color, SUM(amount) AS total
FROM orders
GROUP BY color;
- 聚合下推到数据库,PHP 侧只处理结果集,网络传输与内存占用最小。
- 若数据已在库中且无需 PHP 层二次加工,这是首选。
- 注意:分组字段建议建索引;
SUM对 NULL 的处理需与业务预期对齐。
方案对比
| 方案 | 时间复杂度 | 可读性 | 适用场景 | 注意事项 |
|---|---|---|---|---|
| foreach | O(n) | 高 | 任意内存数组,需多字段累加 | 注意键类型转换(数字字符串键) |
| array_reduce | O(n) | 中 | 函数式风格、链式处理 | 回调开销,大数据量偏慢 |
| SQL GROUP BY | 由 DB 决定 | 高 | 数据在库、结果集小 | 索引与 NULL 语义 |
处理流程
flowchart TD
A[输入数据源] --> B{数据位置}
B -->|内存数组| C[遍历行]
C --> D[以 color 为键累加 amount]
D --> E[输出分组结果]
B -->|数据库| F[SQL GROUP BY color]
F --> G[SUM amount]
G --> E
选型要点
- 数据量在万级以内、结构简单:
foreach足够,性能与可维护性平衡最好。 - 需要链式或函数式表达:
array_reduce,但避免在超大数据集上使用。 - 数据本就存于数据库:优先
GROUP BY,减少 PHP 侧计算与内存压力。 - 颜色值可能存在大小写或空格差异时,先在循环内统一
strtolower(trim()),否则会分裂成多个分组。 - 若
color为数字字符串(如'001'),PHP 数组键会转为整型,输出时需按业务需要还原格式。
© 版权声明
文章版权归作者所有,未经允许请勿转载。