
本文介绍一种高效方法,将对象数组按 type 字段的连续相同值进行分组,生成包含 type 和对应 values 数组的结构化结果,而非全局去重,关键在于识别“相邻重复”而非“所有重复”。
本文介绍一种高效方法,将对象数组按 `type` 字段的**连续相同值**进行分组,生成包含 `type` 和对应 `values` 数组的结构化结果,而非全局去重,关键在于识别“相邻重复”而非“所有重复”。
在实际业务场景中(如时间线事件归类、日志流分段、状态序列聚合),我们常需将具有相同类型且物理位置连续的对象聚合成逻辑区块。例如:多个连续的 "type": "A" 对象应合并为一个区块;一旦中间插入 "type": "B",则前一个 "A" 区块结束,新 "B" 区块开始;后续再次出现连续的 "A",则视为独立的新区块——这正是“按连续相同字段分组”的核心语义。
实现该逻辑最简洁、可读性最强的方式是使用 Array.prototype.reduce() 一次遍历完成:
const data = [
{ object: 1, start: "2018-07-08", end: "2018-12-31", type: "A", user: "ABCD" },
{ object: 2, start: "2018-12-31", end: "2019-06-26", type: "A", user: "ABCD" },
{ object: 3, start: "2019-06-26", end: "2019-12-31", type: "B", user: "PQRS" },
{ object: 4, start: "2019-12-31", end: "2020-06-31", type: "B", user: "PQRS" },
{ object: 5, start: "2021-12-31", end: "2022-12-31", type: "A", user: "ABCD" },
{ object: 6, start: "2012-12-31", end: "2022-06-26", type: "A", user: "ABCD" },
{ object: 7, start: "2022-06-26", end: "2022-12-31", type: "A", user: "ABCD" },
{ object: 8, start: "2022-12-31", end: "2023-06-26", type: "A", user: "ABCD" }
];
const grouped = data.reduce((result, current) => {
// 检查 result 中最后一个分组是否存在,且其 type 是否与当前对象一致
const lastGroup = result.at(-1);
if (lastGroup && lastGroup.type === current.type) {
lastGroup.values.push(current);
} else {
// 创建新分组:固定结构 { type, values: [current] }
result.push({ type: current.type, values: [current] });
}
return result;
}, []);
console.log(grouped);
// 输出符合预期的三段式分组结构
✅ 关键要点说明:
-
result.at(-1)安全获取最后分组(ES2022+,兼容性好;若需支持旧环境,可用result[result.length - 1]替代); - 判断条件
lastGroup && lastGroup.type === current.type确保仅对紧邻的相同 type 进行追加,严格满足“立即连续”语义; - 每个分组结构统一为
{ type: string, values: Array<object> }</object>,语义清晰、易于后续消费(如渲染为折叠面板、生成时间轴等); - 时间复杂度 O(n),空间复杂度 O(n),无额外遍历或查找,性能最优。
⚠️ 注意事项:
- 此方案不改变原始数组顺序,分组完全依赖输入顺序,适用于已按时间/逻辑序排列的数据;
- 若输入数据未排序或存在乱序
type,结果将反映实际相邻关系,而非业务意义上的“同类合并”——请确保上游数据已按业务规则预排序; -
reduce的初始值[]是空数组,确保首次迭代时lastGroup为undefined,自然触发新分组创建。
该模式可轻松扩展:如需同时按 type 和 user 双字段连续分组,只需将判断条件改为 lastGroup?.type === current.type && lastGroup?.user === current.user;若需附加统计信息(如每组起止时间),也可在 push 或 push 后同步计算。掌握这一模式,即可高效处理各类“连续序列聚合”需求。










