
本文介绍如何基于对象属性(如 name)将数组精准拆分为两个子数组:一个包含所有重复出现的元素,另一个仅保留首次出现且无重复的元素,适用于数据清洗与校验场景。
本文介绍如何基于对象属性(如 `name`)将数组精准拆分为两个子数组:一个包含所有重复出现的元素,另一个仅保留首次出现且无重复的元素,适用于数据清洗与校验场景。
在实际前端开发或数据处理中,常需对用户导入的结构化数据(如客户列表、商品清单)进行去重前的诊断性分析——不是简单地“留一删余”,而是明确区分哪些是需人工复核的重复项,哪些是可直接进入业务流程的唯一项。本方案提供一种高效、可读性强且不依赖外部库的原生 JavaScript 实现。
核心思路:分组归集 + 二次筛选
我们利用 Map 按目标属性(如 name)对原始数组进行分组,每个键对应一个包含所有同名对象的数组;随后遍历该 Map,将长度 >1 的组展开为“重复项集合”,长度 ===1 的组则归入“唯一项集合”。
完整实现代码
const customers = [
{ id: 1, name: "John", address: "123 street" },
{ id: 2, name: "Alex", address: "456 street" },
{ id: 3, name: "John", address: "674 street" },
{ id: 4, name: "Stacy", address: "534 street" },
{ id: 5, name: "Blair", address: "634 street" }
];
// 步骤 1:按 name 分组归集
const nameGroups = new Map();
customers.forEach(customer => {
const key = customer.name;
if (!nameGroups.has(key)) {
nameGroups.set(key, []);
}
nameGroups.get(key).push(customer);
});
// 步骤 2:分离重复项与唯一项
const duplicates = [];
const uniques = [];
nameGroups.forEach(group => {
if (group.length > 1) {
duplicates.push(...group); // 所有同名项均视为待校验重复项
} else {
uniques.push(...group); // 仅出现一次的项视为有效唯一项
}
});
console.log("重复项(需人工校验):", duplicates);
// → [{ id:1, name:"John", ... }, { id:3, name:"John", ... }]
console.log("唯一项(可直接处理):", uniques);
// → [{ id:2, name:"Alex", ... }, { id:4, name:"Stacy", ... }, { id:5, name:"Blair", ... }]关键注意事项
- ✅ 稳定性保障:Map 保持插入顺序,因此 uniques 中的元素顺序与原始数组中首次出现的唯一项顺序一致;duplicates 中各组内顺序也与原始出现顺序相同。
- ⚠️ 属性安全性:若 customer.name 可能为 undefined 或 null,建议提前过滤或使用 String(customer.name) 统一转换,避免意外分组。
- ? 可扩展性:只需修改 const key = customer.name 一行,即可适配任意属性(如 email、phone),甚至组合键(如 ${customer.name}-${customer.email})。
- ? 性能表现:时间复杂度为 O(n),空间复杂度为 O(n),适用于数千条以内的常规业务数据量;超大规模数据建议结合 Web Worker 异步处理。
该方法逻辑清晰、无副作用、易于单元测试,是数据预处理阶段分离“问题数据”与“可用数据”的可靠实践方案。









