合并含相同code的JavaScript对象数组结果异常,求修正方案
合并对象数组并累加相同code的times属性问题
我需要合并一个对象数组,移除具有相同code属性的对象并累加其times属性。
给定数据
原始数组
let itemsTimes = [ { item: { code: '0.05' }, times: 1 }, { item: { code: '0.01' }, times: 1 }, { item: { code: '0.02' }, times: 1 }, { item: { code: '0.01' }, times: 1 }, { item: { code: '0.02' }, times: 2 } ];
尝试的代码
let mergedItemTimes = []; itemsTimes.forEach((itemTime, i) => { let j = i + 1 if ((itemsTimes[j])) { itemsTimes.forEach((_, j) => { if (itemTime.item.code === itemsTimes[j].item.code) { itemTime.times += itemsTimes[j].times itemsTimes.splice(j, 1) } }) } mergedItemTimes.push(itemTime) })
输出情况
- 预期输出:
[ { item: { code: '0.05' }, times: 1 }, { item: { code: '0.01' }, times: 2 }, { item: { code: '0.02' }, times: 3 }, ]
- 实际输出:
[ { item: { code: '0.05' }, times: 2 }, { item: { code: '0.02' }, times: 4 }, ]
问题分析
原代码存在多处逻辑错误:
- 遍历中修改原数组导致索引混乱:在
forEach循环里使用splice删除元素,会改变数组长度和元素索引,后续遍历会跳过部分元素或重复处理。 - 嵌套forEach重复累加:每次外层循环都从头遍历整个数组,会把已经累加过的元素再次计算,导致times值错误。
- 无意义的判断条件:
if ((itemsTimes[j]))这个判断完全多余,反而会漏掉数组最后一个元素的处理。
正确解决方案
使用临时映射表存储累加后的对象,以code为键区分,最后将映射表的值转为数组即可,逻辑清晰且不会出现索引问题:
方法一:使用Map实现
const map = new Map(); itemsTimes.forEach(item => { const code = item.item.code; if (map.has(code)) { // 已存在则累加times map.get(code).times += item.times; } else { // 不存在则存入映射表,浅拷贝避免修改原数组 map.set(code, { ...item, item: { ...item.item } }); } }); const mergedItemTimes = Array.from(map.values()); console.log(mergedItemTimes);
方法二:使用普通对象实现
const obj = {}; itemsTimes.forEach(item => { const code = item.item.code; if (obj[code]) { obj[code].times += item.times; } else { obj[code] = { ...item, item: { ...item.item } }; } }); const mergedItemTimes = Object.values(obj); console.log(mergedItemTimes);
两种方法都能得到预期输出,且不会修改原始数组,逻辑更稳定。
内容的提问来源于stack exchange,提问作者user3347778
相关产品推荐
相关产品推荐

