前言
网上数组去重的方法有很多,今天我们就来比较一下哪些方法是比较高效的。如何测试呢?我们就拿26个英文字母循环一万次,十万次,一百万次生成随机的数组来分别比较一下。
生成随机数组
let arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
let newArr = []
for (let i = 0; i <= 1000000; i++) {
let random = Math.floor(Math.random() * 26)
newArr.push(arr[random])
}
1. 双重for循环:很早以前的数组去重方式。
let oneArr = [...newArr]
let start1 = Date.now()
for (let i = 0; i < oneArr.length; i++) {
for (let j = i + 1; j < oneArr.length; j++) {
if (oneArr[i] === oneArr[j]) {
oneArr.splice(j, 1)
j--
}
}
}
let end1 = Date.now()
console.log(`双重for循环:${end1-start1}毫秒`)
2】Set方法(ES6中新增:将循环数组转换为Set,然后再将Set转回数组。由于Set的特性是不允许出现重复元素,所以会自动去除数组中的重复值。
let twoArr = [...newArr]
let start2 = Date.now()
twoArr = [...new Set(twoArr)] //这里也可以写成 twoArr = Array.from(new Set(twoArr))
let end2 = Date.now()
console.log(`Set方法:${end2-start2}毫秒`)
3.indexOf方法: 利用新数组indexOf(数组元素),如果返回是-1就说明新数组里没有该元素,就往新数组里面添加元素。
let threeArr = [...newArr]
let indexArr=[]
let start3 = Date.now()
for (let i = 0; i < threeArr.length; i++) {
if (indexArr.indexOf(threeArr[i]) === -1) {
indexArr.push(threeArr[i])
}
}
let end3 = Date.now()
console.log(`indexOf方法:${end3-start3}毫秒`)
4.sort排序(es6新增):利用 sort方法进行排序和循环,如果原数组的第 i 项和新数组的 i - 1 项不一致,就push进去。
let fourArr = [...newArr]
let start4 = Date.now()
fourArr = fourArr.sort()
let sortArr = []
for (let i = 0; i < fourArr.length; i++) {
fourArr[i] === fourArr[i - 1] ? sortArr : sortArr.push(fourArr[i])
};
let end4 = Date.now()
console.log(`sort 排序 :${end4-start4}毫秒`)
5.for + object:利用对象属性名不能重复这一特点,如果对象中不存在,就可以给push进去。
let fiveArr = [...newArr]
let start5 = Date.now()
let obj = {}
let objArr = []
for (let i = 0; i < fiveArr.length; i++) {
if (!obj[fiveArr[i]]) {
objArr.push(fiveArr[i])
obj[fiveArr[i]] = 1
}
}
let end5 = Date.now()
console.log(`for+object方法 :${end5-start5}毫秒`)
6.includes(ES6新增):利用includes检查新数组是否包含原数组的每一项。 如果不包含,就push进去
let sixArr = [...newArr]
let start6 = Date.now()
let includesArr = []
for (let i = 0; i < sixArr.length; i++) {
includesArr.includes(sixArr[i]) ? includesArr : includesArr.push(sixArr[i])
}
let end6 = Date.now()
console.log(`includes方法 :${end6-start6}毫秒`)
7.filter(ES6新增) + indexOf:利用filter过滤,配合indexOf查找元素。
let sevenArr = [...newArr]
let start7 = Date.now()
let filterArr = sevenArr.filter((item, index) => sevenArr.indexOf(item) === index)
let end7 = Date.now()
console.log(`filter+indexOf :${end7-start7}毫秒`)
8.reduce+includes(ES6新增):reduce不仅可以用于数组的遍历加求和,还可以去重。
let eightArr = [...newArr]
let start8 = Date.now()
let reduceArr = []
// prev 是上一次回调函数的返回值,而 next 就是数组中的当前元素
eightArr.reduce((prev, next) => {
// 如果包含,就返回原数组,不包含,就把新数据追加到数组中
if (reduceArr.includes(next)) {
return reduceArr
} else {
return reduceArr.push(next)
}
}, 0)
let end8 = Date.now()
console.log(`reduce+includes :${end8-start8}毫秒`)
9.Map方法(ES6新增):遍历原始数组,将数组中的每一个元素作为Key存到Map中,因为Map集合中不会出现相同的Key值,因此最终得到的Map中所有的Key值就是去重后的结果
let nineArr = [...newArr]
let start9 = Date.now()
let mapArr = []
let map = new Map()
for (let i = 0; i < nineArr.length; i++) {
if (!map.has(nineArr[i])) { //has(key):判断是否有某个键
map.set(nineArr[i], true); //set(key, value):添加新的键/值对
mapArr.push(nineArr[i]);
}
}
let end9 = Date.now()
console.log(`Map方法 :${end9-start9}毫秒`)
下图是测试结果:
结论
从图上比较不难看出在数据量比较小的情况下,除了双重for循环之外其他的方法效率都还可以,但处理数据较多时,对象去重的方法就明显高效很多,当然Set和Map方法这两种方法也是不错的选择。