数组去重的方法(十种方法)
一、利用ES6 Set去重(ES6中最常用)
代码:
let arr = [1,1,'数组','数组',false,false,undefined,undefined,null,null,NaN,NaN,{},{},[],[]]
function unique(arr){
return Array.from(new Set(arr))
}
console.log(unique(arr))
输出结果:
[ 1, '数组', false, undefined, null, NaN, {}, {}, [], [] ]
总结:
如果不考虑兼容性(Array.from 在 IE浏览器没有得到支持),这种去重的方法代码最少。这种方法还无法去掉“{ } , [ ]”空对象/空数组,后面的高阶方法会添加去掉重复“{ } , [ ]”的方法。
二、利用for嵌套for,然后splice去重(ES5中最常用)
代码:
定义未去重的arr数组不变,所以下面的方法不再写,只写去重的逻辑代码
function unique(arr){
for(let i = 0;i < arr.length; i++){
for(let j = i + 1;j < arr.length; j++){
if(arr[i] === arr[j]){
arr.splice(j,1)
}
}
}
return arr
}
输出结果:
[ 1, '数组', false, undefined, null, NaN, NaN, {}, {}, [], [] ]
总结:
双层循环,外层循环元素,内层循环时比较值。值相同时,则删去这个值。但是NaN、{ }、[ ] 没有去掉,在三等于号比较的情况下,NaN、{ }、[ ] 都是false,关于 ==
和===
可以看片文章 → JavaScript中一个等号、二个等号、 三个等号 的区别(详细例子)
三、利用indexOf去重
代码:
function unique(arr){
if(!Array.isArray(arr)){
console.error('type error!')
return
}
let array = []
for(let i = 0; i < arr.length; i++){
if(array.indexOf(arr[i]) === -1){
array.push(arr[i]);
}
}
return array
}
输出结果:
[ 1, '数组', false, undefined, null, NaN, NaN, {}, {}, [], [] ]
总结:
新建一个空的结果数组,for 循环原数组,使用 indexOf()
判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则push进数组。同样,NaN, [ ], { } 都没有去重掉
四、利用sort()
代码:
function unique(arr){
if(!Array.isArray(arr)){
console.error('type error!')
return
}
let array = [arr.sort()[0]];
for(let i = 1; i < arr.length; i++){
if(arr[i] !== arr[i-1]){
array.push(arr[i])
}
}
return array
}
输出结果:
[ [], [], 1, NaN, NaN, {}, {}, false, null, '数组', undefined ]
总结:
利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对。同样,NaN,[ ], { } 都没有去重掉
五、利用对象的属性不能相同的特点进行去重
代码:
function unique(arr){
if(!Array.isArray(arr)){
console.error('type error!')
return
}
let array = []
let obj = {}
for(let i = 0; i < arr.length; i++){
if(!obj[arr[i]]){
array.push(arr[i])
obj[arr[i]] = 1
}else{
obj[arr[i]]++
}
}
return array
}
输出结果:
[ 1, '数组', false, undefined, null, NaN, {}, [] ]
总结:
利用对象中键名不能重复的特点,将NaN,{ },[ ] 这三个难搞的东西去掉了,至今来看好像是很棒,但是有个BUG,如果在未去重的数组arr中,增加一个 '1'
字符串1的话,此时我们会发现,字符串1被去掉了,大家可以试试,按上面的逻辑写,他是认为数字1和字符串1的键名最后都是相同的所以去掉后面的了,后面有类似的方法完美解决,继续看下去吧!
六、利用includes
代码:
function unique(arr){
if(!Array.isArray(arr)){
console.error('type error!')
return
}
let array = []
for(let i = 0; i < arr.length; i++){
if(!array.includes(arr[i])){
array.push(arr[i])
}
}
return array
}
输出结果:
[ 1, '数组', false, undefined, null, NaN, {}, {}, [], [] ]
总结:
includes()
方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。从输出结果我们可以知道,这个方法可以去掉NaN,但是对于{ } , [ ] 仍然去重不了
七、利用 filter + indexOf
代码:
function unique(arr){
return arr.filter(function(item,index,arr){
return arr.indexOf(item, 0) === index
})
}
输出结果:
[ 1, '数组', false, undefined, null, {}, {}, [], [] ]
总结:
利用 filter
过滤,通过判断 indexOf
查找当前 item 是否存在于 arr 中,如果在过滤后的数组中查找到的索引不等于未去重数组的索引不相等时,返回的就是false,也就是过滤掉,反之相等,则保留;这里的indexOf对 NaN 的检测都是-1,所以输出结果不存在 NaN,同样对于数组和对象也是去不了重的
八、利用 reduce + includes
代码:
function unique(arr){
return arr.reduce((prev,cur) => {
return prev.includes(cur) ? prev : [...prev,cur]
})
}
输出结果:
[ 1, '数组', false, undefined, null, NaN, {}, {}, [], [] ]
总结:
reduce() 方法对数组中的每个元素执行一个提供的reducer,将其结果汇总为单个返回值 – 也就是通过 include()
去重的数组,同include去重的方法,只是将for循环变成reduce方法进行循环判断
九、利用Map数据结构去重
代码:
function unique(arr){
let map = new Map();
let array = [];
for(let i = 0; i < arr.length; i++){
if(map.has(arr[i])){
map.set(arr[i],true)
}else{
map.set(arr[i],false)
array.push(arr[i])
}
}
return array
}
输出结果:
[ 1, '数组', false, undefined, null, NaN, {}, {}, [], [] ]
总结:
创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。它跟 第五种方法利用对象的属性来去重,有进一步优化,他的键名可以是自定义类型,就比如第五种所出现的BUG,数字1和字符串1在Map空间中是可以区分开来的,但有利也有弊,他不能像对象空间一样去区分,空对象或者空数组
十、利用hasOwnProperty(完美)
代码:
function unique(arr){
let obj = {}
return arr.filter(function(item,index,arr){
return obj.hasOwnProperty(typeof item + item) ? false :(obj[typeof item + item] = true)
})
}
输出结果:
[ 1, '数组', false, undefined, null, NaN, {}, [] ]
总结:
回看 第五种方法 > 利用对象的属性不能相同的特点进行去重 使用的原理差不多,但第五种方法并不完美,此时我们利用hasOwnProperty 判断是否存在对象属性,拿到了类型和值的字符串,传给 hasOwnProperty
方法,并且也避免了传入的参数不是字符串的报错,具体可以看这个方法的介绍 → hasOwProperty
结语
关于去重的方法就到此为止,当然还有很多,这里要注意一点,并不是所有去重的对象都是需要包含数组、对象、函数这些比较偏的类型进行去重,在项目中比较常见的还是一些基本类型的去重,所以按照这个标准来回顾上面十种方法,其实都是可以的,大家都可以借鉴参考
文中难免有些错误,如果发现,欢迎指正,希望可以帮到你
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Umbrella_Um/article/details/102680458