
本文介绍如何将包含重复 vendorid 的对象数组按 id 合并,保留各月份字段的非空值(优先取非零/非空),并对缺失月份自动补 0,最终生成结构统一、无重复 id 的规范化数组。
在实际数据处理中(如财务月度汇总、供应商销售统计),原始数据常以“宽表+多行同 ID”的形式存在——同一 VendorID 可能分散在多条记录中,每条仅包含部分月份字段。此时需将其合并为单条记录,并确保所有月份(如 Jan、Feb、Mar)均存在且值合理。
核心思路是:分组聚合 + 字段优先级覆盖 + 缺失字段默认填充。下面提供一个简洁、可读性强且不依赖外部库的纯 JavaScript 实现:
const testarray = [
{ "VendorID": "001", "Jan": "130", "Feb": "500" },
{ "VendorID": "001", "Jan": "0", "Feb": "0", "Mar": "1000" },
{ "VendorID": "002", "Mar": "20" }
];
// 步骤 1:按 VendorID 分组归集
const grouped = testarray.reduce((acc, item) => {
const id = item.VendorID;
if (!acc[id]) acc[id] = {};
Object.assign(acc[id], item); // 后续对象字段会覆盖前面的同名字段(注意:字符串 "0" 不会被跳过)
return acc;
}, {});
// 步骤 2:转换为数组,并统一补全月份字段("0" 视为有效值;若需忽略 "0" 取非零值,见下方增强逻辑)
const finalarray = Object.entries(grouped).map(([VendorID, data]) => ({
VendorID,
Jan: data.Jan ?? "0",
Feb: data.Feb ?? "0",
Mar: data.Mar ?? "0"
}));
console.log(finalarray);
// 输出:
// [
// { VendorID: "001", Jan: "130", Feb: "500", Mar: "1000" },
// { VendorID: "002", Jan: "0", Feb: "0", Mar: "20" }
// ]⚠️ 注意事项:
- 原答案中使用 ...entry, ...line 展开合并时,后出现的对象字段会覆盖先出现的(如第二条 "Jan":"0" 会覆盖第一条 "Jan":"130"),这与需求相悖。正确做法应是保留非空/非零优先值。若需该逻辑,可改用如下安全合并函数:
function mergeWithPriority(...objs) {
const result = {};
objs.forEach(obj => {
Object.keys(obj).forEach(key => {
if (result[key] === undefined || result[key] === "0" || result[key] === "") {
result[key] = obj[key];
}
});
});
return result;
}
// 使用示例(替代 Object.assign):
// Object.assign(acc[id], item) → 改为 acc[id] = mergeWithPriority(acc[id], item)✅ 最佳实践建议:
- 若字段值为数字类型,建议提前 parseInt() 或 Number() 转换,便于后续计算;
- 月份字段列表(["Jan","Feb","Mar"])可抽离为常量,便于动态扩展;
- 生产环境推荐使用 Map 替代普通对象做分组,避免原型污染风险。
该方案兼顾可读性、健壮性与扩展性,适用于各类基于 ID 的对象数组合并场景。










