遇到一个需求,需要去除数组里面相同的项。本身这个需求不复杂,但是考虑到性能问题,则需要好好琢磨一下了。下面我对一些比较常见的方法进行了测试。
先生成一个长度为10万的重复数组:
var arr = [];
for(var i=0; i<100000; i++){
arr.push( Math.floor(Math.random()*100000));
}
var tt = Date.now();
//在此处添加 去除重复数据的测试代码
//abc.......
console.log(Date.now() - tt);
一、利用ES6 Set去重,一行代码搞定,性能极高(ES6中最常用)
//耗时:7ms
Array.from(new Set(arr));
//还可以写成这样,也是耗时:7ms
[...new Set(arr)]
二、利用for嵌套for,然后splice去重(ES5中最常用),性能非常慢
//耗时:8367ms
for(var i=0; i<arr.length-1; i++){
for(var j=i+1; j<arr.length; j++){
if(arr[i]==arr[j]){//第一个等同于第二个,splice方法删除第二个
arr.splice(j,1);
j--;
}
}
}
三、利用 indexOf 或 includes 去重,性能一般般
//耗时:2860ms
var array = [];
for(var i =0; i < arr.length; i++) {
if(array.indexOf(arr[i]) === -1) {
array.push(arr[i])
}
}
arr = array;
//用includes,耗时:2842ms,区别不大
var array = [];
for(var i =0; i < arr.length; i++) {
if(!array.includes( arr[i])) {
array.push(arr[i])
}
}
arr = array;
四、利用sort() 先排序,后去掉所有重复的数据
//耗时:43ms
arr = arr.sort()
var arrry= [arr[0]]; //开启一个新数组,性能很高,但还是比第一种方法低
for(var i =1; i < arr.length; i++) {
if(arr[i] !== arr[i-1]) {
arrry.push(arr[i]);
}
}
arr = array;
//查找相同的对象,修改源数组,耗时:2110ms,相比上面push的方式慢很多
arr = arr.sort()
for(var i =1; i < arr.length; i++) {
if(arr[i] === arr[i-1]) {
arr.splie(i, 1);
i--;
}
}
五、利用filter + Object属性判断,性能还可以
//耗时:80ms
var obj = {}, key;
arr = arr.filter(function(item, index, arr){
key = typeof item + item;
return obj.hasOwnProperty(key) ? false: (obj[key] = true);
})
六、利用filter + indexOf 判断,性能较差
//3693ms
arr = arr.filter(function(item, index, arr){
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return arr.indexOf(item,0) === index;
});
综上所述,最优解是使用第一种方案: es6的新特性
Array.from(new Set(arr));
或
[...new Set(arr)]
在不支持es6的环境下,使用第四方案:利用sort() 先排序,后去掉所有重复的数据
arr = arr.sort()
var arrry= [arr[0]];
for(var i =1; i < arr.length; i++) {
if(arr[i] !== arr[i-1]) {
arrry.push(arr[i]);
}
}
arr = array;
如还有其他更高效的算法请大家留言告知,谢谢~