
本文介绍如何使用 JavaScript 的 reduce() 与 Map 对数组中具有相同 year 和 term 的对象,按条件聚合 worthAmountEGP 字段的总和,并保持原始结构。
本文介绍如何使用 javascript 的 `reduce()` 与 `map` 对数组中具有相同 `year` 和 `term` 的对象,按条件聚合 `worthamountegp` 字段的总和,并保持原始结构。
在实际业务开发中(如教育财务统计、学年预算汇总等场景),我们常需对嵌套在对象数组中的数值字段,按多个维度(如年份 + 学期)进行分组累加。原始数据中可能存在多条相同 year 和 term 的记录,目标是将它们合并为一条,并将 worthAmountEGP 相加,同时保留 year 和 term 字段——这要求聚合键必须联合唯一标识两个条件,而非单独使用 term 或 year。
直接使用普通对象作为累加器(如 acc[term])会导致年份信息丢失,正如提问者最初代码所示:它仅按 term 分组,忽略了 year,从而错误地将 2020 年 Term 2 与 2021 年 Term 2 的金额混加。正确做法是构造一个复合键(composite key),例如 "2020---2",确保每个 (year, term) 组合拥有独立的聚合槽位。
推荐使用 Map 而非普通对象,因其天然支持任意类型键(包括字符串键),且避免原型污染与属性名隐式转换风险(如 year: "constructor" 可能引发意外行为)。以下是标准实现:
const data = [
{ "year": 2020, "term": 1, "worthAmountEGP": 0 },
{ "year": 2020, "term": 2, "worthAmountEGP": 300000 },
{ "year": 2021, "term": 1, "worthAmountEGP": 0 },
{ "year": 2021, "term": 2, "worthAmountEGP": 1000000 },
{ "year": 2021, "term": 1, "worthAmountEGP": 0 },
{ "year": 2021, "term": 2, "worthAmountEGP": 400000 },
{ "year": 2022, "term": 1, "worthAmountEGP": 0 },
{ "year": 2022, "term": 2, "worthAmountEGP": 1000000 }
];
const result = Array.from(
data.reduce((acc, obj) => {
const key = `${obj.year}---${obj.term}`;
if (!acc.has(key)) {
acc.set(key, { ...obj }); // 浅拷贝保留 year/term,初始化 worthAmountEGP
} else {
acc.get(key).worthAmountEGP += obj.worthAmountEGP;
}
return acc;
}, new Map())
).map(([_, value]) => value); // 提取 Map.values() 并转为数组
console.log(result);
// 输出符合预期的 6 条分组结果✅ 关键要点总结:
- 复合键格式建议使用不可歧义的分隔符(如 ---、| 或 \u0000),避免 year: 202, term: 10 与 year: 20, term: 210 键冲突;
- 使用 { ...obj } 进行浅拷贝,确保不修改原始数据;
- 若需排序输出(如按年份升序、学期升序),可在最终结果上调用 .sort((a, b) => a.year - b.year || a.term - b.term);
- 对于超大数据集(>10 万条),可考虑预排序或使用 for...of 循环替代 reduce 以提升可读性与调试便利性。
该方案简洁、健壮、可扩展——如后续需增加 campus 或 department 等新维度,只需扩展键生成逻辑即可,无需重构核心聚合逻辑。

















