JS实现数组去重方法整理

前言

我们先来看下面的例子,当然来源与网络,地址《删除数组中多个不连续的数组元素的正确姿势

我们现在将数组中所有的‘ a’ 元素删除:

var arr = ['a', 'a', 'b', 'c', 'd', 'a', 'a', 'e', 'g', 'a', '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进行操作,如下:

vararr = ['a', 'a', 'b', 'c', 'd', 'a', 'a', 'e', 'g', 'a', 'f'];

arr.forEach(function(value, index) {

  value === 'a' ?deletearr[index] : '';

})

console.log(arr); //[2: "b", 3: "c", 4: "d", 7: "e", 8: "g", 10: "f"]

但是得到的arr其实是一个非常规的数组了,也就是说其实delete主要是用于对对象属性的操作。这确实要根据自己的需求来了。

当然简单的实现如下:

vararr = ['a', 'a', 'b', 'c', 'd', 'a', 'a', 'e', 'g', 'a', 'f'];varnewArr = arr.filter(function(key) {

    returnkey !== 'a'})

console.log(newArr); //["b", "c", "d", "e", "g", "f"]

 下面总结下常用实现方式。

性能测试模板

let arr1 = Array.from(newArray(100000),(item,index) => {

    return index;

})

let arr2 = Array.from(newArray(50000),(item,index) => {

    returnindex + index;

})function distinct(a,b) {

    // 数组去重}

console.time('去重计算时间');

console.log('去重后的长度', distinct(arr1, arr2).length);

console.timeEnd('去重计算时间');

上面创建了两个数组长度,1个10W,1个5W长度的数组,合并到一个数组,然后进行去重,验证下去重的计算时间是多长。

方法一:Array.filter() + indexOf

function distinct(a,b) {

    let arr = a.concat(b);

    returnarr.filter((item,index) => {

        returnarr.indexOf(item) === index;

    })

}

思路就是ES6 中的 Array.filter() 遍历数组,并结合 indexOf 来排除重复项。看下结果:

从截图可以看出,计算时间花费了19753ms的时间。

方法二:使用 for...of + includes()

function distinct(a,b) {

    let arr = a.concat(b)

        let result = []

        for (let i of arr) {

            !result.includes(i) && result.push(i)

        }

        return result

}

这种方式跟Array.filter() + indexOf实现思路差不多,结果如图所示:

从图上可以看出,计算的时间跟Array.filter() + indexOf的时间差不多。

方法三:双重 for 循环

function distinct(a, b) {

    let arr = a.concat(b);

    for(let i=0, len=arr.length; i

        for(let j=i+1; j

            if(arr[i] == arr[j]) {

                arr.splice(j, 1);

                // splice 会改变数组长度,所以要将数组长度 len 和下标 j 减一len--;

                j--;

            }

        }

    }

    return arr

}

优点:简单易懂

缺点:占用内存高,速度慢

看下结果:

方法四:Array.sort()

首先使用 sort() 将数组进行排序

然后比较相邻元素是否相等,从而排除重复项。


function distinct(a, b) {

    let arr = a.concat(b)

    arr.sort(function(a,b){//对数组进行排序才能方便比较returna - b;

    })

    let result = [arr[0]]

    for(let i=1, len=arr.length; i

        arr[i] !== arr[i-1] && result.push(arr[i])

    }

    return result

}


从上面代码可以看出来,做了一次排序和一次循环,所以效率比前面都高,结果如图所示:

可以看出,结果只花了255ms左右时间。

方法五:for...of + Object

利用对象的属性不能相同的特点进行去重,代码如下:

function distinct(a, b) {

    let arr = a.concat(b)

    let result = []

    let obj = {}

    for (let i of arr) {

        if(!obj[i]) {

            result.push(i)

            obj[i] = 1        }

    }

    return result

}

执行结果如图所示:

结果只花费了43ms左右时间。

方法六:ES6的new Set()

function distinct(a, b) {

    returnArray.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 ||function(item) {

    for(vari = 0, j =this.length; i < j; i++) {

        if(this[i] === item) {

            return i;

        }

    }

    return-1;

}

Array.prototype.forEach = Array.prototype.forEach ||function(callback, thisArg) {

    if(!callback ||typeofcallback !== 'function')return;

    for(vari = 0, j =this.length; i < j; i++) {

        callback.call(thisArg, this[i], i,this);

    }

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,875评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,569评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,475评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,459评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,537评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,563评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,580评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,326评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,773评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,086评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,252评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,921评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,566评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,190评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,435评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,129评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,125评论 2 352

推荐阅读更多精彩内容