问题
给定对象数组,例如:
[
{ name: 'neal', age: '18' },
{ name: 'neal', age: '18' },
{ name: 'jane', age: '20' },
]
若 name 与 age 都相同 视为同一业务键重复,给元素打上 flag: true/false(或返回重复组)。
单字段可用 Set;多字段要把字段合成键。
方法一:双循环(直观)
function markDuplicates(collection) {
const n = collection.length;
for (let i = 0; i < n; i++) {
let count = 0;
for (let j = 0; j < n; j++) {
if (
collection[i].name === collection[j].name &&
collection[i].age === collection[j].age
) {
count++;
}
}
collection[i].flag = count > 1;
}
return collection;
}
时间 (O(n^2)),小数据够用。
方法二:哈希键(推荐)
function markDuplicates(collection) {
const keyOf = (o) => `${o.name}\0${o.age}`;
const freq = new Map();
for (const o of collection) {
const k = keyOf(o);
freq.set(k, (freq.get(k) || 0) + 1);
}
for (const o of collection) {
o.flag = freq.get(keyOf(o)) > 1;
}
return collection;
}
时间 (O(n))。键分隔符要选对象字段中不会出现的,或用 JSON.stringify([name, age])。
方法三:groupBy
lodash/underscore 的 groupBy 一次只按一字段时,需要嵌套或自定义 iteratee:
_.groupBy(collection, (o) => `${o.name}|${o.age}`);
长度 > 1 的组即重复。
注意
- 不要直接改业务对象时可返回新数组
age数字与字符串'18'不相等,比较前先规范化- 需要「仅保留唯一」时用 Map 后取 values
小结
多属性判重 = 定义复合键 + 计数/分组。生产优先哈希,面试可先写双循环再优化。
业务场景
- 表格导入前校验「姓名+证件号」是否重复行
- 购物车合并相同 SKU+规格
- 前端表单动态列表提交前去重
打 flag 只是一种展示方式;更常见是直接 filter 掉重复或弹出错误列表。复合键设计要稳定:字段顺序固定、空值策略明确(null 与 '' 是否等同)。