資料去重的需求其實像是lodash這些工具庫已經有成熟完備的實現,並且可以成熟地運用於生產環境。但這並不妨礙我們從思維拓展的角度出發,看看去重可以用幾個想法去實現。本文主要和大家分享javascript數組去重的幾個想法。
首先是常規的雙層循環比對的思路實現
function doubleLoopUniq(arr) { let result = []; for (let i = 0, len = arr.length, isExist; i < len; i++) { // 定义一个变量表示当前元素在 result 中是否存在。 isExist = false; for (let j = 0, rLen = result.length; j < rLen; j++) { if (result[j] === arr[i]) { // 依次对result 中的元素 和 原数组元素进行比对。 isExist = true; break; } } // 最后判断如果不存在,则将此元素插入result !isExist && result.push(arr[i]); } return result; }
借助js內建的indexOf 進行去重
function indexOfUniq(arr) { let result = []; for (let i = 0, len = arr.length; i < len; i++) { // 用indexOf 简化了二层循环的流程 if (result.indexOf(arr[i]) === -1) result.push(arr[i]); } return result; }
排序後前後比對去重
#function sortUniq(arr) { let result = [], last; // 这里解构是为了不对原数组产生副作用 [ ...arr ].sort().forEach(item => { if (item != last) { result.push(item); last = item; } }); return result; }
透過hashTable去重
function hashUniq(arr) { let hashTable = arr.reduce((result, curr, index, array) => { result[curr] = true; return result; }, {}) return Object.keys(hashTable).map(item => parseInt(item, 10)); }
ES6 SET一行程式碼實作去重
function toSetUniq(arr) { return Array.from(new Set(arr)); }
splice 去重(直接操作陣列本身,有副作用)
function inPlaceUniq(arr) { let idx = 0; while (idx < arr.length) { let compare = idx + 1; while (compare < arr.length) { if (arr[idx] == arr[compare]) { arr.splice(compare, 1); continue; } ++compare } ++idx; } return arr; }
最後在nodejs下面簡單跑個測試,看看哪個效率高~
let data = []; for (var i = 0; i < 100000; i++) { data.push(Math.random()) } // 实现一个性能测试的装饰器 function performanceTest(fn, descript) { var a = new Date().getTime(); return function () { fn.apply(this, [].slice.call(arguments, 0)); console.log(descript, new Date().getTime() - a) } } performanceTest(hashUniq, "hashTable")(data) performanceTest(sortUniq, "sortUniq")(data) performanceTest(toSetUniq, "toSetUniq")(data) performanceTest(indexOfUniq, "indexOfUniq")(data) performanceTest(doubleLoopUniq, "doubleLoopUniq")(data) performanceTest(inPlaceUniq, "inPlaceUniq")(data)
結果如下
hashTable 168ms sortUniq 332ms toSetUniq 80ms indexOfUniq 4280ms doubleLoopUniq 13303ms inPlaceUniq 9977ms
延伸思考: 如果陣列內的元素是物件該怎麼重呢?
既然是引用類型,那麼不免會使用到deepEqual,固然這種想法可以解答這道問題,但難免不夠高效。
從上面的測試中也可見透過new Set 和 hashTable 去重是最高效的。
所以毫無疑問,我們要基於這兩種方式去改造,我想用的是hashTable,
另一方面,為了降低深度比較帶來的耗時,我嘗試用JSON.stringify 將引用類型轉換為基本類型。
function collectionUniq(collection) { let hashTable = {}; collection.forEach(item => { hashTable[JSON.stringify(item)] = true; }) return Object.keys(hashTable).map(item => JSON.parse(item)) }
那麼問題來了,我們都知道物件的屬性是無序的,假如資料是這種情況,那就GG了。
let collection = [ { a: 1, b: 2, c: 3 }, { b: 2, c: 3, a: 1 } ]
有一種toHash的思路,在對這個數組進行一次基本的去重之後,為了保證準確,
先遍歷JSON 字串=>
通過charCodeAt()拿到每個字串的unicode 編碼=>
相加得到一個總數,最後再兩兩進行比較,數值相等的就是重複的,這樣就達到去重的效果了。
function toHash(obj) { let power = 1; let res = 0; const string = JSON.stringify(obj, null, 2); for (let i = 0, l = string.length; i < l; i++) { switch (string[i]) { case '{': power *= 2 break case '}': power /= 2 break case ' ': case '\n': case '\r': case '\t': break default: res += string[i].charCodeAt(0) * power } } return res }
這只是一個實現基本的思路,有很大的改進空間,為了減少hash碰撞的可能,可以對一些特殊字元進行權重的增減。
重點是保證碰撞的幾率小到比中大獎還小就可以了。
相關推薦:
以上是實例詳解javascript數組去重的幾個思路的詳細內容。更多資訊請關注PHP中文網其他相關文章!