JavaScript按id关联两个对象数组后按folder分组求和的优化方法
问题描述
需要通过id属性关联两个对象数组(files数组和counts数组),之后按folder属性分组,对每个folder下的所有actions计数累加,最终结果中不需要保留id属性。
文件数组
const files = [{ id: "xxx", folder: "A" },{ id: "bbb", folder: "B" },{ id: "ccc", folder: "B" },{ id: "ddd", folder: "C" },{ id: "aaa", folder: "C" },{ id: "ggg", folder: "A" }]
计数数组
const counts = [{ id: "bbb", actions: { download: 5, seen: 10, shared: 3 } },{ id: "xxx", actions: { download: 2, seen: 5, shared: 8 } },{ id: "ccc", actions: { download: 7, seen: 9, shared: 5 } },{ id: "ggg", actions: { download: 0, seen: 2, shared: 3 } },{ id: "eee", actions: { download: 50, seen: 55, shared: 3 } },{ id: "fff", actions: { download: 5, seen: 4, shared: 3 } }]
期望结果
const result = [{ folder: "A", actions: { download: 2, seen: 7, shared: 11 } },{ folder: "B", actions: { download: 12, seen: 19, shared: 8 } },{ folder: "C" }]
原有实现问题
现有代码通过find方法逐次匹配id,时间复杂度为O(n*m),数组规模大时性能较差;同时存在多次冗余遍历、生成中间数组的问题,可进一步精简。
优化实现方案
核心优化点
- 先把
counts数组转为以id为键的哈希映射,查找复杂度从O(n)降到O(1),整体时间复杂度降至O(n+m),数组越大性能优势越明显 - 跳过中间合并数组的步骤,一次遍历
files直接完成关联、分组、累加,减少多余的对象操作和内存占用
优化后代码
命令式写法(可读性最优)
// 构造id到actions的哈希映射 const countMap = new Map(counts.map(item => [item.id, item.actions])); const groupMap = {}; for (const {id, folder} of files) { // 初始化分组 if (!groupMap[folder]) { groupMap[folder] = { folder }; } const actions = countMap.get(id); // 存在对应计数就累加 if (actions) { if (!groupMap[folder].actions) { groupMap[folder].actions = { download: 0, seen: 0, shared: 0 }; } groupMap[folder].actions.download += actions.download; groupMap[folder].actions.seen += actions.seen; groupMap[folder].actions.shared += actions.shared; } } const result = Object.values(groupMap);
函数式写法(更精简)
const countMap = new Map(counts.map(item => [item.id, item.actions])); const result = Object.values( files.reduce((acc, {id, folder}) => { acc[folder] ??= { folder }; const actions = countMap.get(id); if (actions) { acc[folder].actions ??= { download: 0, seen: 0, shared: 0 }; acc[folder].actions.download += actions.download; acc[folder].actions.seen += actions.seen; acc[folder].actions.shared += actions.shared; } return acc; }, {}) );
两种实现输出结果完全符合预期,性能比原实现提升明显。
内容的提问来源于stack exchange,提问作者user12113809
相关产品推荐
相关产品推荐

