如何按相似ID(含I050前缀匹配)分组对象数组并聚合数值
按规则分组并求和:对象数组聚合解决方案
问题场景
给定原始对象数组:
const originalArray = [ { ID: 'MCHARPENT ', REA: 4, STO: 90, EFFCAR: 178 }, { ID: 'I050MCHE ', REA: 0, STO: 125, EFFCAR: 228 }, { ID: 'I050MCHE ', REA: 0, STO: 106, EFFCAR: 231 }, { ID: 'DBALLAVOINE', REA: 0, STO: 107, EFFCAR: 172 }, { ID: 'DBALLAVOINE', REA: 20, STO: 30, EFFCAR: 100 } ];
需按照以下规则完成分组并对指定字段求和:
- 完全相同的ID归为同一组;
- 若A ID的前3个字符,与B ID中
I050后的前3个字符匹配,则A、B归为同一组; - 分组后以不含
I050的ID作为组标识,对每组的REA、STO、EFFCAR字段值求和,期望输出如下:
[ { ID: 'MCHARPENT', REA: 4, STO: 321, EFFCAR: 637 }, { ID: 'DBALLAVOINE', REA: 20, STO: 137, EFFCAR: 272 } ]
实现方案(JavaScript)
核心思路
- 提取所有非
I050开头的ID作为分组基准,预处理去除空格和重复项; - 遍历数组,为每个元素匹配对应的分组标识:
- 对
I050开头的ID,截取I050后的前3个字符,匹配前3位一致的基准ID; - 非
I050开头的ID直接作为分组标识(去空格);
- 对
- 用对象存储分组累加结果,最后转换为数组得到目标输出。
完整代码
const originalArray = [ { ID: 'MCHARPENT ', REA: 4, STO: 90, EFFCAR: 178 }, { ID: 'I050MCHE ', REA: 0, STO: 125, EFFCAR: 228 }, { ID: 'I050MCHE ', REA: 0, STO: 106, EFFCAR: 231 }, { ID: 'DBALLAVOINE', REA: 0, STO: 107, EFFCAR: 172 }, { ID: 'DBALLAVOINE', REA: 20, STO: 30, EFFCAR: 100 } ]; // 收集所有非I050开头的基准ID(去空格、去重) const baseIds = [...new Set( originalArray .filter(item => !item.ID.startsWith('I050')) .map(item => item.ID.trim()) )]; // 初始化分组映射,用于累加计算 const groupMap = {}; originalArray.forEach(item => { let groupId; const trimmedId = item.ID.trim(); if (trimmedId.startsWith('I050')) { // 截取I050后的前3个字符作为匹配键 const matchKey = trimmedId.slice(3, 6); // 找到前3位匹配的基准ID groupId = baseIds.find(id => id.startsWith(matchKey)); } else { groupId = trimmedId; } // 初始化分组结构(若不存在) if (!groupMap[groupId]) { groupMap[groupId] = { ID: groupId, REA: 0, STO: 0, EFFCAR: 0 }; } // 累加字段值 groupMap[groupId].REA += item.REA; groupMap[groupId].STO += item.STO; groupMap[groupId].EFFCAR += item.EFFCAR; }); // 将分组映射转换为数组,得到最终结果 const result = Object.values(groupMap); console.log(result);
代码说明
- 基准ID处理:用
Set快速去重,确保每个基准ID只出现一次; - 分组匹配逻辑:通过
startsWith和slice实现ID的规则匹配,精准找到对应分组; - 累加计算:遍历数组时直接更新分组映射的字段值,避免多次遍历,提升效率。
内容的提问来源于stack exchange,提问作者Steven
相关产品推荐
相关产品推荐

