JavaScript 数组去重:11 种方法对比与实战指南
文章目录
- 前言
- 一、使用 `Set` 数据结构
- 二、使用 `filter` + `indexOf`
- 三、使用 `reduce` 累加器
- 四、双重 `for` 循环
- 五、利用对象属性唯一性
- 六、先排序后去重
- 七、使用 `Map` 数据结构
- 八、使用 `includes` 方法
- 九、优化处理 `NaN` 的 `filter` 方法
- 十、利用 `findIndex`
- 十一.利用`Set`和展开运算符处理多维数组
- 总结
前言
一、使用 Set
数据结构
function uniqueBySet(arr){return [...new Set(arr)]
}
利用 Set
数据结构中重复元素会被自动过滤的特点。
- 优点:简单高效,时间复杂度为 O(n)。
- 注意:无法区分对象引用类型,但是可以处理
NaN
。
二、使用 filter
+ indexOf
function uniqueByFilter(arr){return arr.filter((item,index)=> arr.indexOf(item) === index)
}
使用 indexOf
返回元素首次出现的索引,若非当前索引则过滤。
- 注意:时间复杂度为 O(n²),不处理
NaN
,因为indexOf(NaN)
始终返回 -1。
三、使用 reduce
累加器
function uniqueByReduce(arr) {return arr.reduce((acc, cur) => acc.includes(cur) ? acc : [...acc, cur], []);
}
使用 reduce
检查当前元素是否存在于累加数组中,存在则不添加,不存在则添加。
- 注意:时间复杂度为 O(n²),空间复杂度较高。
四、双重 for
循环
function uniqueByLoop(arr) {const result = [];for (let i = 0; i < arr.length; i++) {let isDuplicate = false;for (let j = 0; j < result.length; j++) {if (arr[i] === result[j]) {isDuplicate = true;break;}}if (!isDuplicate) result.push(arr[i]);}return result;
}
通过循环嵌套比较元素是否重复。
- 注意:时间复杂度为 O(n²),性能较差。
五、利用对象属性唯一性
function uniqueByObj(arr){const obj = {}return arr.filter(item=>{const key = typeof item + JSON.stringify(item)return obj.hasOwnProperty(key) ? false :(obj[key] = true) })
对象的键名唯一,通过序列化来区分不同类型及对象。
- 注意:
JSON.stringify
无法处理函数、循环引用,性能一般。
六、先排序后去重
function uniqueBySort(arr) {const sortedArr = [...arr].sort();return sortedArr.filter((item, index) => index === 0 || item !== sortedArr[index - 1]);
}
对数组排序后,重复的元素会相邻,然后直接过滤。
- 注意:原数组顺序会被改变。
七、使用 Map
数据结构
function uniqueByMap(arr){const map = new Map()return arr.filter(item=>!map.has(item) && map.set(item,true))
}
利用 Map
键的唯一性可以快速判断元素是否存在。
- 优点:时间复杂度为 O(n),可以正确处理对象引用和
NaN
。
八、使用 includes
方法
function uniqueByIncludes(arr) {const result = [];for (const item of arr) {if (!result.includes(item)) result.push(item);}return result;
}
在遍历时检查元素是否已存在于结果数组。
- 注意:时间复杂度为 O(n²),不能处理
NaN
。
九、优化处理 NaN
的 filter
方法
function uniqueWithNaN(arr) {const hasNaN = arr.some(item => Number.isNaN(item));const result = arr.filter((item, index) => {if (Number.isNaN(item)) {// 仅保留第一个NaNreturn !hasNaN || (index === arr.findIndex(i => Number.isNaN(i)));}return arr.indexOf(item) === index;});return result;
}
单独处理 NaN
,确保只保留第一个出现的 NaN
。
- 优点:该方法兼容
NaN
去重。
十、利用 findIndex
function uniqueByFindIndex(arr) {return arr.filter((item, index) => {return arr.findIndex(i => i === item) === index;});
}
使用 findIndex
和 indexOf
方法类似,但是可以处理自定义处理 NaN
。
十一.利用Set
和展开运算符处理多维数组
function uniqueMultidimensionalArray(arr) {return Array.from(new Set(arr.flat(Infinity)));
}
首先利用flat
方法将多维数组扁平化,然后利用Set
去除重复元素,最后通过Array.from
将Set
转换会数组
- 注意:该方法只能处理元素为基本类型或可序列化的对象的多维数组。如果数组中包含函数,循环引用等特殊对象,
flat
方法和Set
可能无法正确处理
总结
- 简单场景:优先使用
Set
或Map
,简洁高效。 - 兼容性要求:使用
filter + indexOf
或者双重循环。 - 含
NaN
或者对象:选择Map
或改进的对象属性方法。 - 排序无影响:排序后去重效率高 。