选用map而非set或object,因其支持任意类型键且保持插入顺序;filter遍历时用map记录已见元素,实现首次出现顺序去重,并可封装为按指定键去重的高阶函数。

用 filter 结合 Map 去重,核心是利用 Map 的键唯一性和插入顺序保留特性,在遍历时记录已见元素,同时保持原数组首次出现的顺序。
为什么选 Map 而不是 Set 或 Object?
Map 支持任意类型作为键(包括对象、函数、NaN),且严格按插入顺序迭代;Set 虽也保序,但不能直接用于 filter 的“状态记忆”逻辑(需额外变量);Object 键会强制转字符串,丢失类型信息(如 {a:1} 和 [1] 都变成 "[object Object]")。
基础写法:filter + Map 实现顺序去重
在 filter 回调中,用一个外部 Map 记录是否见过当前项。首次遇到时设为 true 并返回 true,后续遇到返回 false:
示例(基础数字/字符串):
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
const arr = [1, 2, 3, 2, 4, 1, 5];
const seen = new Map();
const unique = arr.filter(item => {
if (seen.has(item)) return false;
seen.set(item, true);
return true;
});
// → [1, 2, 3, 4, 5]
处理复杂类型(如对象)需自定义 key
直接用对象作 Map 键是可行的(引用相等),但若想按内容去重(如两个相同结构的对象视为重复),需生成稳定 key:
- 简单场景:用
JSON.stringify(仅适用于纯对象、无函数/undefined/Symbol/循环引用) - 健壮方案:用第三方库(如
fast-deep-equal+ 缓存 Map)或手写序列化逻辑 - 推荐折中:对数组中对象提取唯一标识字段(如
id或name)作为 Map 键
示例(按 id 去重):
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice2' }, // 同 id,视为重复
{ id: 3, name: 'Charlie' }
];
const seenIds = new Map();
const uniqueUsers = users.filter(user => {
if (seenIds.has(user.id)) return false;
seenIds.set(user.id, true);
return true;
});
// → [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }]
封装成可复用函数
把逻辑抽成高阶函数,支持传入提取 key 的方法:
const uniqueBy = (arr, keyFn = x => x) => {
const seen = new Map();
return arr.filter(item => {
const key = keyFn(item);
if (seen.has(key)) return false;
seen.set(key, true);
return true;
});
};
// 使用
uniqueBy([1, 2, 2, 3], x => x); // [1, 2, 3]
uniqueBy(users, u => u.id); // 按 id 去重
uniqueBy(users, u => u.name); // 按 name 去重
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










