
本文介绍如何将包含 list 和 book 属性的对象数组中,相邻且 book 值相同的对象进行合并:将其 list 数组合并为一个长数组,其余结构保持不变。
本文介绍如何将包含 `list` 和 `book` 属性的对象数组中,**相邻且 `book` 值相同的对象**进行合并:将其 `list` 数组合并为一个长数组,其余结构保持不变。
在实际开发中(如日志聚合、时间序列分组、UI 列表折叠等场景),我们常需对具有相同分类标识(如本例中的 book 字段)的连续数据块进行归并处理,而非全局去重。关键在于“连续性”——仅当相同 book 的对象在原数组中物理相邻时才合并,中间一旦被其他 book 打断,即视为新分组。
核心思路
遍历原数组,维护一个结果数组 result。对每个当前对象 obj:
- 若
result非空,且其末尾对象的book与obj.book相同 → 将obj.list元素展开追加到末尾对象的list中; - 否则 → 将
obj的深拷贝(仅浅拷贝list数组)推入result。
✅ 注意:必须使用
obj.list.slice()或[...obj.list]创建新数组引用,避免后续修改影响原始数据。
推荐实现方式(for...of 循环)
const array = [
{ list: [1, 2, 3], book: 'A' },
{ list: [2, 1, 4], book: 'B' },
{ list: [3, 5, 8], book: 'A' },
{ list: [4, 8, 5], book: 'B' },
{ list: [2, 8, 9], book: 'B' },
{ list: [6, 2, 7], book: 'B' },
{ list: [9, 7, 4], book: 'A' },
{ list: [1, 4, 7], book: 'B' },
{ list: [1, 9, 3], book: 'A' },
{ list: [5, 2, 3], book: 'A' },
{ list: [7, 4, 2], book: 'A' }
];
const result = [];
for (const obj of array) {
const lastObj = result[result.length - 1];
if (lastObj && lastObj.book === obj.book) {
lastObj.list.push(...obj.list); // 合并 list
} else {
result.push({ list: [...obj.list], book: obj.book }); // 浅拷贝 list,保留原对象结构
}
}
console.log(result);
// 输出符合预期的合并结果
替代方案:reduce 函数式写法
const result = array.reduce((acc, obj) => {
const last = acc[acc.length - 1];
if (last && last.book === obj.book) {
last.list.push(...obj.list);
} else {
acc.push({ list: [...obj.list], book: obj.book });
}
return acc;
}, []);
⚠️ 注意事项
-
不依赖外部库:上述实现纯 JS,无需 D3 或 Lodash;原回答中误用
d3.range和错误字段名(如price、trend)属于逻辑混淆,应避免; -
不可变性考量:若需完全不可变(不修改原数组 也不修改原对象的 list),所有
list都必须深拷贝(但本例中list仅为数字数组,[...arr]已足够); -
空数组安全:
result[result.length - 1]在result为空时返回undefined,逻辑天然安全; - 性能友好:单次遍历,时间复杂度 O(n),空间复杂度 O(n)(结果数组)。
该方法简洁、健壮、易理解,是处理“连续分组合并”问题的标准实践。










