JavaScript數組去重性能測試

本篇文章參考以下博文

前言

  最近在處理數據時搜到一個去重方法,發現使用起來逼格很高,在此總結記錄一下衆多去重方法,並比較一下不同方法間的性能,作爲以後裝逼的談資。

測試模板

  通過 from 方法創建兩個數組,一個是 十萬數據,一個是 五萬數據 ,連接這兩個數組之後去重,查看去重時間。

// distinct.js

let arr1 = Array.from(new Array(100000), (x, index)=>{
    return index
})

let arr2 = Array.from(new Array(50000), (x, index)=>{
    return index+index
})

let start = new Date().getTime()
console.log('開始數組去重')

function distinct(a, b) {
    // 數組去重
}

console.log('去重後的長度', distinct(arr1, arr2).length)

let end = new Date().getTime()
console.log('耗時', end - start)

一、數組去重性能測試

1.1 Array.filter() + indexOf

  這個方法是通過 filter 篩選,數組中每一個元素的索引,是不是等於它在數組中第一次出現的位置,如果是說明這個元素第一次出現,可以 return 出去,如果不是說明前面已經有相同的數據了,就不 return

function distinct(a, b) {
    let arr = a.concat(b);
    return arr.filter((item, index)=> {
        return arr.indexOf(item) === index
    })
}

  執行時間如下。
在這裏插入圖片描述
  由於是第一個,還沒有參照,先做個記錄。

1.2 for 循環嵌套

  外層循環遍歷,內層循環檢查是否重複。

function distinct(a, b) {
    let arr = a.concat(b);
    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--;
            }
        }
    }
    return arr
}

在這裏插入圖片描述
  難怪大佬們都不喜歡用 for 循環,這效率,差的不是一個量級。

1.3 for…of + includes()

  跟上面的用法差不多,都是循環,只不過把 for 變成了 for…of 當然也可以使用 indexOf() 代替 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
}

在這裏插入圖片描述
  看到 for…of 的效率了不,以後乖乖把 for 都替換掉。

1.4 利用hasOwnProperty

  利用 hasOwnProperty 判斷是否存在對象屬性,利用了對象屬性不能重複的特點。

function distinct(a, b) {
    let arr = a.concat(b)
    var obj = {};
    return arr.filter(function(item, index, arr){
        return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
    })
} 

在這裏插入圖片描述
  這個性能提升就很明顯了,直接從八千多降到一百多。

1.5 Array.sort()

  先快排,然後查看相鄰數據有沒有重複的。

function distinct(a, b) {
    let arr = a.concat(b)
    arr = arr.sort()
    let result = [arr[0]]

    for (let i=1, len=arr.length; i<len; i++) {
        arr[i] !== arr[i-1] && result.push(arr[i])
    }
    return result
}

在這裏插入圖片描述
  驚不驚喜,意不意外,你就說迪奧不迪奧吧。

1.6 new Set()

  這個比較經典了,通過 ES6 Set 對象實現,應爲 Set 的成員具有唯一性,感覺天生是爲去重而創造的。

function distinct(a, b) {
    return Array.from(new Set([...a, ...b]))
}

在這裏插入圖片描述
  Emmmmmm…這說明在去重的時候,專門做去重的,就是比專門做排序的方法快,快一毫秒也是快。

1.7 利用Map數據結構去重

  準確的說,這是用了 map 對象裏面的一些方法, map 中存儲的鍵值對會提供一些數組沒有的方法,來達到去重的目的。

function distinct(a, b) {
    let arr = a.concat(b)
    let map = new Map();
    let array = new Array();  // 數組用於返回結果
    for (let i = 0; i < arr.length; i++) {
      if(map.has(arr[i])) {  // 如果有該key值
        map.set(arr[i], true); 
      } else { 
        map.set(arr[i], false);   // 如果沒有該key值
        array .push(arr[i]);
      }
    } 
    return array ;
}  

在這裏插入圖片描述
   ES6 的東西就是好用,這幾個新提供的對象在性能方面優秀的一批。

1.8 for…of + Object

  這個是利用對象的屬性不會重複的特性,上面1.4方法也是用了屬性不重複特性,不過本方法是直接利用特性去重,而上面的方法是把屬性不重複的這一特性轉化成了代碼,然後再通過代碼驗證。

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
}

在這裏插入圖片描述
  這有點嚇人,恐怖如斯。 JS 有個特點,它的某些極致的功能,很多都是通過它的一些特性去解決的,這就很有意思。

1.9 reduce

  給大夥來個娛樂局,下面這個是通過 reduce 的回調函數, reduce 中回調函數各個形參的含義可以戳這裏

function distinct(a, b) {
    let arr = a.concat(b)
    arr = arr.reduce((prev, current) => {
        return prev.includes(current) ? prev : prev.concat(current);
    }, []);

    return arr
}

在這裏插入圖片描述

  娛樂局嘛,這個的時間有點長的離譜了,不過 reduce 方法用來去重,不是去簡單數據類型的,而是用來對引用數據類型進行去重的,比如說:

let arr = [{id: 123, name: 1}, {id: 123, name: 2}, {id: 123, name: 3}]
let newobj = {}; 
arr = arr .reduce((prev, current) => {
	newobj[current.id] ? '' : newobj[current.id] = prev.push(curVal); 
	return prev
}, [])
//arr[{id: 123, name: 1}]

  上面的方法中,就是對數組中的對象按照 id 屬性進行去重的。

總結

爲了方便查看,我做了個對照表格

名次 方法 耗時(ms)
1 for…of + Object 16
2 new Set() 23
3 Array.sort() 24
4 Map數據結構 30
5 hasOwnProperty 131
6 for…of + includes() 8660
7 Array.filter() + indexOf 8852
8 for 嵌套 14546
9 reduce 58715

  上面測試用到for循環的時候,都先把arr.length計算出來,然後再進行比較,而不是直接 i<arr.length 這是爲了提升 for 循環的效率,具體提升有多少,各位可以跳轉下面這個博客,提升的性能超乎你的想象。

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

JavaScript,for循環效率測試,不同遍歷循環測試,數組添加效率測試,大數組拼接測試,for循環遍歷修改 和 string replace效率




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章