
本文介绍如何利用 array.prototype.reduce 高效地按 supplierid 分组、过滤 status === 3 的发票,并汇总 invoicetotal,最终生成去重且含合计字段的供应商对象数组。
本文介绍如何利用 array.prototype.reduce 高效地按 supplierid 分组、过滤 status === 3 的发票,并汇总 invoicetotal,最终生成去重且含合计字段的供应商对象数组。
在处理发票类业务数据时,常需按供应商维度聚合有效(如已确认、已完成)状态的金额。本例中,仅 status === 3 的发票参与计算,目标是输出每个唯一供应商的 supplierId、supplierName 和所有符合条件发票的 invoicesTotal 总和。
核心思路是:用一个普通对象(或 Map)作为累加器,以 supplierId 为键缓存供应商摘要;遍历每张发票时,先确保该供应商条目存在,再根据状态决定是否累加金额。相比先去重再二次遍历求和,此方式仅需一次 reduce,时间复杂度为 O(n),性能更优。
以下是推荐实现(使用 plain object 作为 reduce 累加器):
const result = Object.values(
invoices.reduce((acc, { supplierId, supplierName, invoiceTotal, status }) => {
// 若该 supplierId 尚未初始化,则创建默认对象
if (!acc[supplierId]) {
acc[supplierId] = {
supplierId,
supplierName,
invoicesTotal: 0
};
}
// 仅当 status === 3 时累加金额
if (status === 3) {
acc[supplierId].invoicesTotal += invoiceTotal;
}
return acc;
}, {})
);
✅ 关键点说明:
- 使用 Object.values() 将累加器对象转换为数组,天然实现“去重”(同 supplierId 覆盖写入);
- 解构赋值 { supplierId, supplierName, invoiceTotal, status } 提升可读性与性能;
- 条件判断 if (status === 3) 确保仅统计目标状态,避免错误累加(如示例中 SUP123 的第二张发票 status: 1 被跳过);
- 不依赖 Map 可减少语法冗余,但若需支持非字符串键(如 symbol 或对象),可替换为 new Map() 并配合 map.get(key) ??= {...}。
运行后,result 即为所求:
[
{
"supplierId": "SUP123",
"supplierName": "Roger Enterprises Ltd",
"invoicesTotal": 2200
},
{
"supplierId": "SUP456",
"supplierName": "Steve Systems Ltd",
"invoicesTotal": 1200
}
]
⚠️ 注意事项:
- 若原始数据中同一 supplierId 对应多个不同 supplierName(数据不一致),当前逻辑会保留首次出现的名称。如需校验一致性,可在 reduce 内添加断言或日志;
- invoiceTotal 应为数值类型,若可能为字符串,请在累加前转为数字:Number(invoiceTotal) 或 +invoiceTotal;
- 如需支持空数组安全处理,可在 reduce 前增加 if (!Array.isArray(invoices) || invoices.length === 0) return [];。
该方案简洁、健壮、符合函数式编程思想,适用于各类按字段分组聚合场景。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











