PHP 按 color 分组并累加字段值的高效实现

问题定义与数据准备

按 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 数组键会转为整型,输出时需按业务需要还原格式。
© 版权声明

相关文章