如何合并具有相同 ID 的对象数组中的行

1次阅读

如何合并具有相同 ID 的对象数组中的行

本文介绍如何将包含重复 vendorid 的对象数组按 id 合并,自动聚合各月字段(如 jan、feb、mar),缺失字段补 0,最终生成结构统一、无重复 id 的规范化数组。

在实际数据处理中,我们常遇到原始数据以“稀疏记录”形式存在:同一供应商(VendorID)的销售或费用信息分散在多条记录中,每条仅填充部分月份字段。目标是将其归并为一条完整记录,实现字段优先级覆盖(后出现的非空值覆盖前值)并补齐缺失字段为默认值(如 0)。以下是一种简洁、可读性强且不依赖外部库的原生 javaScript 实现方案。

核心思路

  1. 遍历原始数组,对每个对象按 VendorID 进行分组归并;
  2. 使用 Array.prototype.find() 定位已存在的同 ID 记录
  3. 利用对象展开语法 {…existing, …new} 实现字段合并——注意:后出现的属性会覆盖先出现的(即“后写入优先”),这恰好满足“用新值补充旧记录”的需求;
  4. 最后统一标准化字段结构,确保所有输出对象都包含 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 }));

该方案兼顾可读性、健壮性与扩展性,适用于报表汇总、前端数据预处理等典型场景。

text=ZqhQzanResources