数组去重方法分析
数组去重方法分析
方法一、通过新数组的indexOf方法
1 Array.prototype.unique = Array.prototype.unique || function () { 2 var result = []; 3 this.forEach(function (v) { 4 if(result.indexOf(v) < 0){ 5 //result.indexOf(v) >= 0 表示这个 v 已经在数组result[]里面了 6 // < 0 则表示这个 v 还没在数组里面 没有的才push 有的就不push了 所以不会出现两个相等的 v 。 7 result.push(v); 8 } 9 }); 10 return result; 11 };
方法二、通过原数组的indexOf方法
1 Array.prototype.unique = Array.prototype.unique || function () { 2 var result = []; 3 for(var i = 0; i <this.length; i++) { 4 if (this.indexOf(this[i]) == i) { 5 //this.indexOf(this[i]) !== i 表面这个元素已经出现过了 == i表示第一次出现,这时才push到result里面去。 6 result.push(this[i]); 7 } 8 } 9 return result; 10 };
方法三、使用hash表
1 Array.prototype.unique = Array.prototype.unique || function () { 2 var hash = {}; //新建一个hash表 3 var result = []; //新建一个数组 4 for (var i = 0; i <this.length; i++){ 5 if(!hash[this[i]]){ //如果hash表中没有这项 6 hash[this[i]] = true; //就把这项添加到hash表中去 7 result.push(this[i]); //并且把这项添加到新数组 8 } 9 } 10 return result; 11 };
为了检验三种方法性能的优劣,我写了一个测试程序 ,这里我创建 一个长度为len的数组,数组的每一项为0 - wth的随机数组,给len和wth赋不同值,再在network里面看他们各自执行时间。
1 var len = 1000, wth = 1000; 2 var arr = new Array(len); 3 for(var i = 0; i < wth; i++){ 4 arr[i] = Math.floor(Math.random()*wth); 5 } 6 console.log(arr.unique());
检验数组长度和纬度不同时三种方法的效率(chrome浏览器下),结果如下:
1、当 len =1000, wth = 1000时
三种方法执行时间基本一样,都在30ms左右;
2、设置 len = 1000, wth = 10000时
三种方法执行时间按顺序分别为:100ms左右、120ms左右、38ms左右;
3、设置len = 10000, wth = 10000时
此时测试出来的时间与第二种设置基本一样!
4、设置len =100000,wth = 10000时
三种方法执行时间按顺序分别为:120ms左右、9~10s之间、60ms左右;
5、设置len = 100000,wth = 100000时
三种方法执行时间分别为:6-7s之间、9~10s之间、60ms左右
数据很明显:时间上最稳定的方式是第三种--hash表法,其余两种什么鬼啊....
当数组长度纬度较小时,用indexOf方法种方法勉强完成任务,性能劣与hash表法,其中方法一优于方法二;
当数组长度纬度较大时,6-7s是什么鬼...9-10秒又是什么鬼...这个时候这两种方法都只有gg。。。
简单分析一下:
第一二中方法用到了数组的indexOf方法,这种方法会寻找参数再数组中第一次出现的位置,很显然,js引擎在实现这个方法是会遍历数组直到找到目标为止,
所以这种方法会消耗很多时间。
第三种方法用的是hash表,把已经出现过的通过下标的形式存入一个Object内,而下标的引用要比用indexOf搜索数组快很多!当然,这种方法也不是完美的,
因为多了一个hash表,内存占用更多,相当于用空间换时间。。
方法四、Set结构法
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set 本身是一个构造函数,用来生成 Set 数据结构。看看下面的代码。
1 const s = new Set(); 2 [1,3,2,3,6,7,2].forEach(x => s.add(x)); 3 console.log(s); 4 //{1,3,2,6,7}
运行结果是{1,3,2,6,7},很显然这不是一个数组。要将它转化为一个数组,那再看看下面的方法。
1 const set = new Set([1,2,3,2,5]); 2 const array = Array.from(set); 3 console.log(array); 4 //[1,2,3,5]
这里用到了Array的from方法,其实还可以封装一个利用set结构转数组的方法,如下:
1 function derepetition(array){ 2 return Array.from(new Set(array)); 3 } 4 console.log(derepetition([1,3,2,3,5])); 5 //[1,3,2,5]
其实还有更简便的方法...
1 const set1 = new Set([1,2,3,3,5]); 2 [...set1]; //[1,2,3,5]
这里就简直不讲道理了,不过是真心的简便!!!!