
本文介绍如何将包含重复键(如 year)的对象数组,按该键合并为唯一项,并将其对应数组字段(如 worksSummaryDetailsObj)进行扁平化拼接。核心方法是使用 reduce 构建以键为索引的哈希表,再通过 Object.values() 提取结果。
本文介绍如何将包含重复键(如 `year`)的对象数组,按该键合并为唯一项,并将其对应数组字段(如 `workssummarydetailsobj`)进行扁平化拼接。核心方法是使用 `reduce` 构建以键为索引的哈希表,再通过 `object.values()` 提取结果。
在实际开发中,我们常遇到结构类似如下、需按某个字段(如 year)去重并聚合子数组的场景:
const worksSummaryDetailsArr = [
{ year: 2020, worksSummaryDetailsObj: [{id: 1}, {id: 2}] },
{ year: 2021, worksSummaryDetailsObj: [{id: 3}, {id: 4}] },
{ year: 2022, worksSummaryDetailsObj: [{id: 5}] },
{ year: 2021, worksSummaryDetailsObj: [{id: 6}, {id: 7}] },
{ year: 2022, worksSummaryDetailsObj: [{id: 8}, {id: 9}, {id: 10}] }
];
目标是将相同 year 的对象合并,同时将其 worksSummaryDetailsObj 数组深度拼接(非覆盖),最终得到:
[
{ year: 2020, worksSummaryDetailsObj: [{id: 1}, {id: 2}] },
{ year: 2021, worksSummaryDetailsObj: [{id: 3}, {id: 4}, {id: 6}, {id: 7}] },
{ year: 2022, worksSummaryDetailsObj: [{id: 5}, {id: 8}, {id: 9}, {id: 10}] }
]
✅ 推荐解法:使用 Array.prototype.reduce() 配合对象累加器
const merged = Object.values(
worksSummaryDetailsArr.reduce((acc, item) => {
const { year } = item;
if (!acc[year]) {
// 首次出现该年份:直接存入
acc[year] = { ...item };
} else {
// 已存在:合并 worksSummaryDetailsObj 数组
acc[year] = {
year,
worksSummaryDetailsObj: [
...acc[year].worksSummaryDetailsObj,
...item.worksSummaryDetailsObj
]
};
}
return acc;
}, {})
);
? 关键说明:
- 使用普通对象 {} 作为累加器(acc),以 year 为 key 存储归并后的对象;
- Object.values() 将键值对转为数组,天然去重且保持逻辑顺序(注意:数值 key 会按升序排列,若需严格原始年份顺序,建议后续按 year 排序);
- 合并时使用展开运算符 ... 确保 worksSummaryDetailsObj 是浅拷贝拼接,避免引用污染。
⚠️ 注意事项:
- 若 worksSummaryDetailsObj 中存在重复对象(如相同 id),此方案不会自动去重;如需去重,请额外结合 Map 或 filter() + findIndex() 处理;
- 不推荐使用 Set + map/filter 组合(如提问者原代码),因其无法正确聚合嵌套数组,且 Set 对对象判等基于引用,无法识别内容重复;
- 若数据量极大(>10万项),可考虑使用 for...of 替代 reduce 以提升性能与内存可控性。
? 扩展建议:封装为可复用函数
function mergeByField(arr, key, concatFields = []) {
return Object.values(
arr.reduce((acc, item) => {
const keyValue = item[key];
if (!acc[keyValue]) {
acc[keyValue] = { ...item };
} else {
concatFields.forEach(field => {
if (Array.isArray(item[field]) && Array.isArray(acc[keyValue][field])) {
acc[keyValue][field] = [...acc[keyValue][field], ...item[field]];
}
});
}
return acc;
}, {})
);
}
// 调用示例
const result = mergeByField(worksSummaryDetailsArr, 'year', ['worksSummaryDetailsObj']);
该函数支持按任意字段合并,并可灵活指定多个需拼接的数组型字段,提升代码复用性与可维护性。










