如何高效按name键对嵌套数组内compensatedItems分组统计
JavaScript 嵌套数组按name字段分组计数高效实现
核心思路是用哈希表做分组存储,实现线性时间复杂度O(k)(k为所有compensatedItems下元素的总个数),没有冗余遍历,是该场景下的理论最优方案。
最优实现代码(普通对象版,性能最佳)
适合绝大多数场景,无原型对象的属性查找速度最快,无额外依赖:
const groupItems = (sourceArr) => { // 创建无原型纯净对象作为哈希表,避免原型链属性冲突,提升查找速度 const groupMap = Object.create(null); for (const parent of sourceArr) { // 兼容边界情况:compensatedItems不存在或不是数组时跳过 if (!Array.isArray(parent.compensatedItems)) continue; for (const item of parent.compensatedItems) { const itemName = item.name; if (groupMap[itemName]) { // 已存在同名分组,直接累加计数 groupMap[itemName].count += 1; } else { // 新分组,拷贝原条目属性,初始化count为1 groupMap[itemName] = { ...item, count: 1 }; } } } // 哈希表的值转为数组即为最终结果 return Object.values(groupMap); }; // 调用即可得到你需要的结果 const res = groupItems(arr);
ES6 Map 版本
如果存在name为非字符串类型(比如Symbol、数字类型的key)的场景,可以用Map替代纯净对象,性能和前者基本持平:
const groupItems = (sourceArr) => { const groupMap = new Map(); for (const parent of sourceArr) { if (!Array.isArray(parent.compensatedItems)) continue; for (const item of parent.compensatedItems) { const itemName = item.name; if (groupMap.has(itemName)) { groupMap.get(itemName).count += 1; } else { groupMap.set(itemName, { ...item, count: 1 }); } } } return Array.from(groupMap.values()); };
性能注意事项
- 避免使用
Array.find在结果数组里查找匹配分组的写法,这种写法每处理一个元素都要遍历一次结果数组,时间复杂度会退化为O(n²),数据量超过1000条后性能会明显下降,示例如下(不推荐):
❌ 低性能反例
// 数据量大时请勿使用 const badResult = arr .flatMap(i => i.compensatedItems) .reduce((acc, cur) => { const exist = acc.find(i => i.name === cur.name); exist ? exist.count++ : acc.push({...cur, count: 1}); return acc; }, []);
- 以上给出的实现默认相同
name的条目,id、reason等其他属性值完全一致,和你提供的示例场景匹配。如果存在同name但其他属性不同的需求,可以按需调整合并逻辑。
内容的提问来源于stack exchange,提问作者dragi
相关产品推荐
相关产品推荐

