
本文介绍如何将多层嵌套的数组(每个子数组包含若干对象)扁平化合并,并依据 Time 与 Element 的组合键去重,最终按语义分组为多个独立子数组。核心思路是使用 Set 追踪已出现的键值对,结合 map + filter 或 reduce 实现高效、可读性强的合并逻辑。
本文介绍如何将多层嵌套的数组(每个子数组包含若干对象)扁平化合并,并依据 `time` 与 `element` 的组合键去重,最终按语义分组为多个独立子数组。核心思路是使用 `set` 追踪已出现的键值对,结合 `map` + `filter` 或 `reduce` 实现高效、可读性强的合并逻辑。
在实际开发中,我们常遇到类似结构的数据:一个顶层数组,其每个元素又是一个对象数组(如时间序列数据、多源采集结果等)。目标不是简单地扁平化(flat()),而是保留语义分组——即把所有 Element: 'Hi' 的对象归为一组(去重后)、Element: 'Hello' 归为另一组,依此类推。关键约束在于:同一 (Time, Element) 组合仅保留首次出现的对象,且最终输出仍为嵌套数组结构(每个子数组对应一个唯一的 Element 值)。
✅ 推荐方案:map + filter + 全局 Set(清晰易维护)
该方法逻辑直观:遍历每一层子数组,对其中每个对象生成唯一键(如 '45$Hi'),用 Set 记录已处理过的键;若键未存在,则保留该对象,并加入 Set;最后过滤掉空子数组。
const arrays = [
[{ Time: 45, Element: 'Hi' }, { Time: 55, Element: 'Hi' }, { Time: 65, Element: 'Hi' }],
[{ Time: 45, Element: 'Hi' }, { Time: 55, Element: 'Hi' }, { Time: 65, Element: 'Hi' },
{ Time: 25, Element: 'Hello' }, { Time: 35, Element: 'Hello' }, { Time: 20, Element: 'Hello' }],
[{ Time: 45, Element: 'Hi' }, { Time: 55, Element: 'Hi' }, { Time: 65, Element: 'Hi' },
{ Time: 25, Element: 'Hello' }, { Time: 35, Element: 'Hello' }, { Time: 20, Element: 'Hello' },
{ Time: 100, Element: 'Bye' }]
];
const seenKeys = new Set();
const mergedGroups = arrays
.map(subArray =>
subArray.filter(obj => {
const key = `${obj.Time}$${obj.Element}`; // 构建唯一标识(防 Time/Element 冲突)
if (seenKeys.has(key)) return false;
seenKeys.add(key);
return true;
})
)
.filter(subArray => subArray.length > 0); // 移除空子数组
console.log("Merged Array:", mergedGroups);
// 输出:
// [
// [{Time:45,Element:'Hi'}, {Time:55,Element:'Hi'}, {Time:65,Element:'Hi'}],
// [{Time:25,Element:'Hello'}, {Time:35,Element:'Hello'}, {Time:20,Element:'Hello'}],
// [{Time:100,Element:'Bye'}]
// ]⚙️ 替代方案:单次 reduce(节省一次遍历,适合大数据量)
若性能敏感(如数千个子数组),可改用 reduce 合并过滤与收集逻辑,避免额外的 .filter() 遍历:
const seenKeys = new Set();
const mergedGroups = arrays.reduce((acc, subArray) => {
const filtered = subArray.filter(obj => {
const key = `${obj.Time}$${obj.Element}`;
if (seenKeys.has(key)) return false;
seenKeys.add(key);
return true;
});
if (filtered.length > 0) acc.push(filtered);
return acc;
}, []);
// 结果同上⚠️ 注意事项与最佳实践
-
键构造必须唯一且稳定:推荐用
JSON.stringify({Time, Element})替代字符串拼接(如${Time}$${Element}),以防Time或Element自身含$或特殊字符。但本例中数据简单,拼接法更轻量。 -
不依赖
Element单独去重:注意题设要求是按(Time, Element)全字段组合去重,而非仅Element。例如{Time:45,Element:'Hi'}和{Time:55,Element:'Hi'}是不同项,不可合并或丢弃。 - 原始顺序保留:上述方法天然保持各对象在首次出现时的子数组内顺序,符合预期。
-
不可变性考虑:代码未修改原数组,符合函数式编程习惯;如需深度克隆,可在
filter内返回structuredClone(obj)(现代环境)或手动浅拷贝。 -
扩展性提示:若需按其他字段(如
id)去重,只需调整key生成逻辑即可,无需重构主流程。
通过以上方法,你既能精准实现“按复合键去重 + 语义分组”的需求,又能保证代码简洁、可读、可维护。
立即学习“Java免费学习笔记(深入)”;


















