数组去重也算是前端面试的一道经典题了,这里我们来总结一下具体有哪些方法,各自的逻辑:
1. 双层for循环
function distinct(arr){
let len = arr.length
for(let i = 0; i < len; i++){
for(let j = i + 1; j < len; j++){
if(arr[i] === arr[j]){
arr.splice(j, 1)
len--
j--
}
}
}
return arr
}
这种方式比较简单,但时间复杂度较高为O(n^2)
。大致思路就是从第一个元素开始,判断和剩余元素是否重复,如果重复通过splice
删除重复元素,并继续向后遍历判断。
2. filter+indexOf
function distinct(arr){
return arr.filter((item, index) => {
return arr.indexOf(item) === index
})
}
逻辑也很简单,数组的filter
函数,会将数组中满足条件的元素筛选出,生成一个新的数组并返回。这里我们只去判断arr当前元素的indexof
得到的索引是否与自己的index相同,相同说明当前元素不重复或者是重复元素的第一个,返回true。如果不相等说明是重复元素且不是重复元素中的第一个,返回false。filter
将索引返回true中的item集合起来,返回一个新的数组就是结果。
3. sort+相邻判断
function distinct(arr){
let newArr = []
arr.sort((i, j) => {
if(i < j){
return -1
}else if(i > j){
return 1
}
return 0
})
for(let i = 0; i < arr.length; i++){
arr[i] !== arr[i + 1] ? newArr.push(arr[i]) : ''
}
return newArr
}
具体逻辑其实就是,先排序,再一次遍历,判断当前元素与下一个元素是否相同,如果相同说明是重复数据,且不是重复元素中的最后一个。如果不同说明没有重复元素或者是重复元素中的最后一个,推入新数组。其实这里的一次for也可以用reduce
来代替
4. Set去重
function distinct(arr){
return [...new Set(arr)]
}
这个代码最简单了,首先set
本来就是一个不可有重复数据的集合。我们将new Set(arr)
已经去除重复数据,不过得到的是一个set结构的数据。这里我们可以通过结构复制...
将数据取出放到数组中,也可以通过Array.from()
将其专为数组结构。
5. for+includes
function distinct(arr){
let newArray = []
for(let i = 0; i < arr.length; i++){
!newArray.includes(arr[i]) ? newArray.push(arr[i]) : ''
}
return newArray
}
逻辑就是一次for
循环,判断当前元素在新数组中是否存在,如果不存在推入新数组,如果存在进入下一次循环。
6. reduce+include
function distinct(arr){
return arr.reduce((res, item) => {
res.includes(item) ? '' : res.push(item)
return res
}, [])
}
这里的逻辑同上
7. Map去重
function distinct(arr){
let map = new Map()
for(let i = 0; i < arr.length; i++){
map.set(arr[i], 0)
}
return [...map.keys()]
}
一次循环,将数组中的元素作为key值存储在map中,因为map中key不可重复,所以即使数据重复,也只会覆盖原有的数据。最终通过map.keys
拿到map的所有key值,不过结果是一个迭代器,我们仍可以用…解构赋值的方取出所有元素放入数组中或者使用Array.from()
将其转为数组。