JavaScript中的数组去重方法详解
字数 986 2025-11-11 18:55:48
JavaScript中的数组去重方法详解
数组去重是JavaScript中常见的需求,涉及多种实现方法和性能考量。下面将从基础到高级逐步讲解不同的去重方式及其原理。
1. 使用Set(ES6最简单的方法)
原理:Set是ES6引入的数据结构,其元素唯一性可自动过滤重复值。
步骤:
- 将数组转换为Set,重复值会被自动去除。
- 将Set转回数组。
代码示例:
const arr = [1, 2, 2, 3, 4, 4, 5];
const uniqueArr = [...new Set(arr)]; // 或 Array.from(new Set(arr))
console.log(uniqueArr); // [1, 2, 3, 4, 5]
优点:代码简洁,效率高(时间复杂度O(n))。
缺点:无法处理特殊场景(如对象元素去重)。
2. 使用filter与indexOf
原理:利用indexOf返回首次出现索引的特性,筛选出第一次出现的元素。
步骤:
- 遍历数组,检查当前元素的索引是否等于
indexOf返回的索引。 - 若相等则保留,否则过滤。
代码示例:
const arr = [1, 2, 2, 3, 4, 4, 5];
const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index);
console.log(uniqueArr); // [1, 2, 3, 4, 5]
优点:兼容性好(ES5)。
缺点:时间复杂度O(n²),大数据量时性能较差。
3. 使用reduce
原理:通过累加器逐步构建不含重复值的数组。
步骤:
- 初始化空数组作为累加器。
- 遍历原数组,若当前元素不在累加器中则追加。
代码示例:
const arr = [1, 2, 2, 3, 4, 4, 5];
const uniqueArr = arr.reduce((acc, cur) => acc.includes(cur) ? acc : [...acc, cur], []);
// 或使用push提升性能:
// const uniqueArr = arr.reduce((acc, cur) => {
// if (!acc.includes(cur)) acc.push(cur);
// return acc;
// }, []);
优点:逻辑清晰,可灵活扩展。
缺点:包含检查(includes)会导致O(n²)复杂度。
4. 使用Map(处理对象去重)
原理:利用Map的键唯一性,以特定规则(如序列化)作为键去重。
步骤:
- 创建Map,遍历数组并以元素特征(如JSON.stringify)为键存储。
- 提取Map的值作为结果。
代码示例(对象去重):
const arr = [{id: 1}, {id: 2}, {id: 1}];
const map = new Map();
arr.forEach(item => map.set(item.id, item)); // 以id为键去重
const uniqueArr = Array.from(map.values());
console.log(uniqueArr); // [{id: 1}, {id: 2}]
优点:可自定义去重规则,适合复杂数据类型。
缺点:需明确去重依据(如属性名)。
5. 性能优化:一次遍历+对象缓存
原理:通过对象属性查询(O(1))替代数组查询(O(n)),提升效率。
步骤:
- 创建空对象和结果数组。
- 遍历数组,若元素未在对象中出现则标记并存入结果数组。
代码示例:
const arr = [1, 2, 2, 3, 4, 4, 5];
const uniqueArr = [];
const cache = {};
arr.forEach(item => {
if (!cache[item]) {
cache[item] = true;
uniqueArr.push(item);
}
});
优点:时间复杂度O(n),性能最优。
缺点:仅适用于基本类型(对象需转为字符串键)。
总结与选择建议
- 简单场景:优先使用
Set(代码简洁,效率高)。 - 兼容性要求:使用
filter+indexOf(ES5)。 - 复杂数据类型:结合
Map或自定义哈希规则。 - 极致性能:一次遍历+对象缓存(避免嵌套循环)。
通过理解不同方法的原理与适用场景,可灵活应对实际开发中的去重需求。