问题:如何实现数组去重?
数组去重是前端面试中的高频题目,本文汇总多种实现方案及适用场景。
核心方案
| 方法 | 时间复杂度 | 空间复杂度 | 特点 |
|---|---|---|---|
| Set | O(n) | O(n) | 最简洁,推荐 |
| filter + indexOf | O(n²) | O(n) | 语义清晰 |
| reduce | O(n²) | O(n) | 函数式风格 |
| sort + filter | O(n log n) | O(n) | 适合有序数组 |
| Map | O(n) | O(n) | 支持复杂类型 |
具体实现
1. Set(推荐)
// 最简洁
const arr = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(arr)];
// [1, 2, 3]
// 或者
const unique = Array.from(new Set(arr));原理:Set 自动去重
2. filter + indexOf
const unique = arr.filter((item, index) => {
return arr.indexOf(item) === index;
});原理:保留首次出现的元素,双层循环
3. reduce
const unique = arr.reduce((prev, cur) => {
return prev.includes(cur) ? prev : [...prev, cur];
}, []);原理:累积唯一元素,每次 includes 也是 O(n)
4. sort + filter
const unique = arr.slice().sort().filter((item, index, arr) => {
return !index || item !== arr[index - 1];
});原理:排序后相同元素相邻,去除相邻重复
5. Map(支持复杂类型)
function unique(arr) {
const map = new Map();
return arr.filter(item => !map.has(item) && map.set(item, true));
}原理:Map 的 key 可以是对象
方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| Set | 代码简洁,性能好 | 不适合对象数组 |
| filter+indexOf | 语义清晰 | O(n²) 性能差 |
| reduce | 可链式操作 | 代码稍长 |
| sort | 适合有序数组 | 会改变原数组顺序 |
| Map | 支持对象去重 | 代码稍复杂 |
面试追问
Q:如何去除对象数组中的重复项?
const arr = [{a:1}, {a:1}, {a:2}];
const unique = [...new Map(arr.map(item => [JSON.stringify(item), item])).values()];Q:如何保留最后一个重复项而不是第一个?
const unique = arr.filter((item, index) => {
return arr.lastIndexOf(item) === index;
});知识图谱
- 父级概念:算法与数据结构
- 关联概念:
- 如何实现数组扁平化?
- JavaScript — 实现语言
- 时间复杂度 — 方案选择依据
- Set — Set 数据结构
参考延伸
- JavaScript 数组去重方法汇总
- LeetCode 26. Remove Duplicates from Sorted Array