前言
我们先来看下面的例子,当然来源与网络,地址《删除数组中多个不连续的数组元素的正确姿势》
我们现在将数组中所有的‘ a’ 元素删除:
var arr = ['a','a','b','c','d','e','g','f'];
arr.forEach(function(value,index) {
value === 'a' ? arr.splice(index,1) : '';
})
console.log(arr); //["a","b","c","d","a","e","g","f"]
只要相邻的‘ a’ 元素, 都没被删除, splice不但可以删除元素本身, 还同时可以减少数组长度( 就是抹去一切痕迹),
这样导致后续的数组元素会代替已经删除的元素的位置, 但是循环是按照数组的下标按顺序删除, 这样就会漏掉迁移的元素。
看到网上有网友在说使用delete进行操作,如下:
var arr = ['a','f']; arr.forEach(function(value,index) { value === 'a' ? delete arr[index] : ''; }) console.log(arr); [2: "b",3: "c",4: "d",7: "e",8: "g",10: "f"]
但是得到的arr其实是一个非常规的数组了,也就是说其实delete主要是用于对对象属性的操作。这确实要根据自己的需求来了。
当然简单的实现如下:
]; var newArr = arr.filter((key) { return key !== 'a' }) console.log(newArr); ["b","f"]
下面总结下常用实现方式。
性能测试模板
let arr1 = Array.from(new Array(100000),(item,index) => { return index; }) let arr2 = Array.from(new Array(50000),1)">return index + index; }) distinct(a,b) { 数组去重 } console.time('去重计算时间'); console.log('去重后的长度',distinct(arr1,arr2).length); console.timeEnd('去重计算时间');
上面创建了两个数组长度,1个10W,1个5W长度的数组,合并到一个数组,然后进行去重,验证下去重的计算时间是多长。
方法一:Array.filter() + indexOf
a.concat(b); return arr.filter((item,1)"> { return arr.indexOf(item) === index; }) }
思路就是ES6 中的 Array.filter() 遍历数组,并结合 indexOf 来排除重复项。看下结果:
从截图可以看出,计算时间花费了19753ms的时间。
方法二:使用 for...of + includes()
a.concat(b) let result = [] for (let i of arr) { !result.includes(i) && result.push(i) } result }
这种方式跟Array.filter() + indexOf实现思路差不多,结果如图所示:
从图上可以看出,计算的时间跟Array.filter() + indexOf的时间差不多。
方法三:双重 for 循环
for (let i=0,len=arr.length; i<len; i++) { for (let j=i+1; j<len; j++) { if (arr[i] == arr[j]) { arr.splice(j,1); splice 会改变数组长度,所以要将数组长度 len 和下标 j 减一 len--; j--; } } } arr }
优点:简单易懂
缺点:占用内存高,速度慢
看下结果:
方法四:Array.sort()
首先使用 sort() 将数组进行排序
然后比较相邻元素是否相等,从而排除重复项。
a.concat(b) arr.sort(function(a,b){ 对数组进行排序才能方便比较 return a - b; }) let result = [arr[0]] for (let i=1,1)">) { arr[i] !== arr[i-1] && result.push(arr[i]) } result }
从上面代码可以看出来,做了一次排序和一次循环,所以效率比前面都高,结果如图所示:
可以看出,结果只花了255ms左右时间。
方法五:for...of + Object
a.concat(b) let result = [] let obj = {} (let i of arr) { if (!obj[i]) { result.push(i) obj[i] = 1 } } result }
执行结果如图所示:
结果只花费了43ms左右时间。
方法六:ES6的new Set()
return Array.from(new Set([...a,...b])) }
Set数据结构,它类似于数组,其成员的值都是唯一的。
利用Array.from将Set结构转换成数组。
结果如图所示:
从结果看出来该方法执行只花了151ms左右的时间。
总结
从上面几种方法得出如下结论:
- 数组去重要么使用for...of + Object方式,要么使用ES6的 new Set()方式。
- 从执行结果看for...of + Object的效率应该是最高的(只在当前量级的计算结果来看)。
附录
附录中添加浏览器Array对象支持indexOf和forEach的polyfill:
Array.prototype.indexOf = Array.prototype.indexOf || (item) { for (var i = 0,j = this.length; i < j; i++if (this[i] === item) { i; } } return -1; } Array.prototype.forEach = Array.prototype.forEach || (callback,thisArg) { if (!callback || typeof callback !== 'function') ; ) { callback.call(thisArg,this[i],i,this); } }