You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Node.js的JavaScript数组中按多键分组并多属性求和的最优方法

在Node.js中按多Key分组并多属性求和的高效实现

嘿,这个需求在数据处理场景里太常见了!咱们直接切入正题:要按Phase和Step两个字段分组,同时对每组的Value1、Value2分别求和,还要保证效率最优。

最高效的实现方案:原生Array.reduce()

毫无疑问,用原生的reduce方法是最高效的——它只需要一次遍历数组,时间复杂度为O(n)(n是数组元素总数),这是理论上的最优复杂度,毕竟你总得处理每个元素一次对吧?

核心思路是用一个对象作为临时映射表,把Phase+Step的组合作为唯一键,遍历过程中不断累加对应分组的数值,最后再把映射表转成目标数组格式。

直接上代码(完全贴合你的示例输入输出):

const input = [
  { Phase: "Phase 1", Step: "Step 1", Value1: "15", Value2: "5" },
  { Phase: "Phase 1", Step: "Step 2", Value1: "20", Value2: "10" },
  { Phase: "Phase 2", Step: "Step 1", Value1: "25", Value2: "15" },
  { Phase: "Phase 2", Step: "Step 2", Value1: "30", Value2: "20" },
  { Phase: "Phase 1", Step: "Step 1", Value1: "35", Value2: "25" },
  { Phase: "Phase 1", Step: "Step 2", Value1: "40", Value2: "30" },
  { Phase: "Phase 2", Step: "Step 1", Value1: "45", Value2: "35" },
  { Phase: "Phase 2", Step: "Step 2", Value1: "50", Value2: "40" }
];

// 构建分组映射:键是Phase+Step的唯一组合,值是累加后的对象
const groupedMap = input.reduce((acc, currentItem) => {
  // 用分隔符生成唯一键,避免不同组合的键冲突(比如Phase是"Phase1|Step"的情况)
  const groupKey = `${currentItem.Phase}|${currentItem.Step}`;

  // 如果分组不存在,初始化一个新的累加对象
  if (!acc[groupKey]) {
    acc[groupKey] = {
      Phase: currentItem.Phase,
      Step: currentItem.Step,
      Value1: 0,
      Value2: 0
    };
  }

  // 把字符串类型的数值转成数字累加(示例里Value是字符串,必须转类型)
  acc[groupKey].Value1 += Number(currentItem.Value1);
  acc[groupKey].Value2 += Number(currentItem.Value2);

  return acc;
}, {});

// 把映射对象转成数组,并把数值转回字符串(和示例输出格式一致)
const output = Object.values(groupedMap).map(item => ({
  ...item,
  Value1: String(item.Value1),
  Value2: String(item.Value2)
}));

console.log(output);
// 输出结果完全匹配你的期望

关键细节说明

  • 分组键的生成:用|作为分隔符是为了避免键冲突——比如如果某个Phase值包含空格或特殊字符,用分隔符能保证不同的Phase+Step组合生成唯一的键。你也可以用其他不会出现在字段值里的分隔符,比如###。
  • 类型处理:示例里的Value1、Value2是字符串类型,所以必须转成数字再累加,最后再转回字符串保持格式一致。如果你的实际数据是数字类型,可以跳过转字符串的步骤。
  • 扩展性:如果之后要增加分组键(比如加Status)或者求和属性(比如加Value3),只需要修改键的生成逻辑和累加部分即可,非常灵活。

其他可选方案(效率稍低)

如果你项目里已经在用Lodash,也可以用_.groupBy来实现,但它需要两次遍历(先分组再对每个分组求和),效率略低于原生reduce:

const _ = require('lodash');

const grouped = _.groupBy(input, item => `${item.Phase}|${item.Step}`);
const output = Object.values(grouped).map(group => ({
  Phase: group[0].Phase,
  Step: group[0].Step,
  Value1: String(group.reduce((sum, item) => sum + Number(item.Value1), 0)),
  Value2: String(group.reduce((sum, item) => sum + Number(item.Value2), 0))
}));

这个方案代码更简洁,但性能不如原生reduce,适合已经引入Lodash的场景。

总结

处理这类分组求和需求,原生Array.reduce()是最优选择——线性时间复杂度,内存占用低,不需要额外依赖。哪怕是处理百万级别的大数据量,这个方案也能稳定运行。

内容的提问来源于stack exchange,提问作者NRaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 11:27:52