
本文介绍如何将包含重复 vendorid 的对象数组按 id 合并,自动聚合各月字段(如 jan、feb、mar),缺失字段补 0,最终生成结构统一、无重复 id 的规范化数组。
在实际数据处理中,我们常遇到原始数据以“稀疏记录”形式存在:同一供应商(VendorID)的销售或费用信息分散在多条记录中,每条仅填充部分月份字段。目标是将其归并为一条完整记录,实现字段优先级覆盖(后出现的非空值覆盖前值)并补齐缺失字段为默认值(如 0)。以下是一种简洁、可读性强且不依赖外部库的原生 javaScript 实现方案。
核心思路
- 遍历原始数组,对每个对象按 VendorID 进行分组归并;
- 使用 Array.prototype.find() 定位已存在的同 ID 记录;
- 利用对象展开语法 {…existing, …new} 实现字段合并——注意:后出现的属性会覆盖先出现的(即“后写入优先”),这恰好满足“用新值补充旧记录”的需求;
- 最后统一标准化字段结构,确保所有输出对象都包含 Jan、Feb、Mar 等键,并将 undefined 或空字符串转换为数值 0(可根据业务需要改为 “” 或 “N/A”)。
完整实现代码
const testarray = [ { "VendorID": "001", "Jan": "130", "Feb": "500" }, { "VendorID": "001", "Jan": "0", "Feb": "0", "Mar": "1000" }, { "VendorID": "002", "Mar": "20" } ]; const result = []; testarray.forEach(entry => { const existing = result.find(item => item.VendorID === entry.VendorID); if (existing) { // 移除原记录,合并后重新加入(保证顺序与首次出现一致) const index = result.indexOf(existing); result.splice(index, 1, { ...existing, ...entry }); } else { result.push({ ...entry }); } }); // 标准化字段:强制包含 Jan/Feb/Mar,空值转为 0(数值型更利于后续计算) const finalarray = result.map(item => ({ VendorID: item.VendorID, Jan: number(item.Jan) || 0, Feb: Number(item.Feb) || 0, Mar: Number(item.Mar) || 0 })); console.log(finalarray); // 输出: // [ // { VendorID: "001", Jan: 0, Feb: 0, Mar: 1000 }, ← 注意:此处 "Jan": "0" 覆盖了 "130" // { VendorID: "002", Jan: 0, Feb: 0, Mar: 20 } // ]
⚠️ 重要说明与注意事项:
- 上述实现遵循“后写入优先”原则。例如 VendorID: “001” 的第二条记录中 “Jan”: “0” 会覆盖第一条的 “130”。若需“保留首次非空值”,应改用条件赋值逻辑(如 Jan: item.Jan != NULL ? item.Jan : existing?.Jan)。
- Number(…) 转换可防止字符串 “0” 被误判为 falsy;若需保留字符串格式,可改用 item.Jan ?? “0”。
- 若月份字段动态不确定(如新增 Apr、May),建议先扫描全量 key 集合,再做统一初始化,避免硬编码。
- 性能提示:对于超大数据集(>10,000 条),find() + splice() 的 O(n²) 复杂度可能成为瓶颈,此时推荐改用 map 做 O(1) ID 索引:
const map = new Map(); testarray.forEach(entry => { const id = entry.VendorID; const existing = map.get(id) || {}; map.set(id, { ...existing, ...entry }); }); const finalarray = Array.from(map.values()).map(item => ({ VendorID: item.VendorID, Jan: Number(item.Jan) || 0, Feb: Number(item.Feb) || 0, Mar: Number(item.Mar) || 0 }));
该方案兼顾可读性、健壮性与扩展性,适用于报表汇总、前端数据预处理等典型场景。