摘要:但是這并不妨礙我們從思維拓展的角度出發(fā),看看去重可以用幾種思路去實現(xiàn)。首先是常規(guī)的雙層循環(huán)比對的思路實現(xiàn)定義一個變量表示當前元素在中是否存在。依次對中的元素和原數(shù)組元素進行比對。重點是保證碰撞的幾率小到比中大獎還小就可以了。
前端在日常開發(fā)中或多或少都會碰到有對數(shù)據(jù)去重的需求,實際上,像是lodash這些工具庫已經(jīng)有成熟完備的實現(xiàn),并且可以成熟地運用于生產(chǎn)環(huán)境。但是這并不妨礙我們從思維拓展的角度出發(fā),看看去重可以用幾種思路去實現(xiàn)。
首先是常規(guī)的雙層循環(huán)比對的思路實現(xiàn)
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 中的元素 和 原數(shù)組元素進行比對。 isExist = true; break; } } // 最后判斷如果不存在,則將此元素插入result !isExist && result.push(arr[i]); } return result; }
借助 js內(nèi)置的indexOf 進行去重
function indexOfUniq(arr) { let result = []; for (let i = 0, len = arr.length; i < len; i++) { // 用indexOf 簡化了二層循環(huán)的流程 if (result.indexOf(arr[i]) === -1) result.push(arr[i]); } return result; }
排序后前后比對去重
function sortUniq(arr) { let result = [], last; // 這里解構(gòu)是為了不對原數(shù)組產(chǎn)生副作用 [ ...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一行代碼實現(xiàn)去重
function toSetUniq(arr) { return Array.from(new Set(arr)); }
splice 去重(直接操作數(shù)組本身,帶副作用)
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()) } // 實現(xiàn)一個性能測試的裝飾器 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)
結(jié)果如下
hashTable 168ms sortUniq 332ms toSetUniq 80ms indexOfUniq 4280ms doubleLoopUniq 13303ms inPlaceUniq 9977ms
延伸思考: 如果數(shù)組內(nèi)的元素是對象該怎么去重呢?
既然是引用類型,那么不免會使用到deepEqual,固然這種思路可以解答這道問題,但難免不夠高效。
從上面的測試中也可見通過new Set 和 hashTable 去重是最高效的。
所以毫無疑問,我們要基于這兩種方式去改造,我想用的是hashTable,
另一方面,為了降低深度比較帶來的耗時,我嘗試用JSON.stringify 將引用類型轉(zhuǎn)化為基本類型。
function collectionUniq(collection) { let hashTable = {}; collection.forEach(item => { hashTable[JSON.stringify(item)] = true; }) return Object.keys(hashTable).map(item => JSON.parse(item)) }
那么問題來了,我們都知道對象的屬性是無序的,假如數(shù)據(jù)是這種情況,那就GG了。
let collection = [ { a: 1, b: 2, c: 3 }, { b: 2, c: 3, a: 1 } ]
有一種toHash的思路,在對這個數(shù)組進行一次基本的去重之后,為了保證準確,
先遍歷JSON 字符串 =>
通過 charCodeAt()拿到每個字符串 的 unicode 編碼 =>
相加得到一個總數(shù),最后再兩兩進行比較,數(shù)值相等的就是重復的,這樣就達到去重的效果了。
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 " ": case " ": case " ": break default: res += string[i].charCodeAt(0) * power } } return res }
這只是一個實現(xiàn)基本的思路,有很大的改進空間,為了減少hash碰撞的可能,可以對一些特殊字符進行權(quán)重的增減。
重點是保證碰撞的幾率小到比中大獎還小就可以了。
2018.2.8
上面是一個比較清奇的思路,常規(guī)的做法,實際上還是應(yīng)該從優(yōu)化深度比較的效率入手。
看到一個很好的實現(xiàn)思路,是一個優(yōu)先判錯的思路,通過預設(shè)各種前置條件來避免高代價的循環(huán),這種思路盡管在數(shù)據(jù)量小的時候因為前置判斷可能有一些微乎其微的性能損耗,但是數(shù)據(jù)量越大,優(yōu)勢就越明顯了。感興趣的可以了解下。
https://github.com/epoberezki...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107306.html
摘要:否則存入結(jié)果數(shù)組。否則存入結(jié)果數(shù)組排序后相鄰去除法雖然原生數(shù)組的方法排序結(jié)果不怎么靠譜,但在不注重順序的去重里該缺點毫無影響。實現(xiàn)思路給傳入數(shù)組排序,排序后相同值相鄰,然后遍歷時新數(shù)組只加入不與前一值重復的值。 1.遍歷數(shù)組法 實現(xiàn)思路:新建一新數(shù)組,遍歷傳入數(shù)組,值不在新數(shù)組就加入該新數(shù)組中;注意點:判斷值是否在數(shù)組的方法indexOf是ECMAScript5 方法,IE8以下不支持...
摘要:數(shù)組去重,一般都是在面試的時候才會碰到,一般是要求手寫數(shù)組去重方法的代碼。如果是被提問到,數(shù)組去重的方法有哪些你能答出其中的種,面試官很有可能對你刮目相看。數(shù)組去重的方法一利用去重中最常用不考慮兼容性,這種去重的方法代碼最少。 數(shù)組去重,一般都是在面試的時候才會碰到,一般是要求手寫數(shù)組去重方法的代碼。如果是被提問到,數(shù)組去重的方法有哪些?你能答出其中的10種,面試官很有可能對你刮目相看...
摘要:數(shù)組去重的幾種方法遍歷數(shù)組法這是最簡單的數(shù)組去重方法,實現(xiàn)思路新建一新數(shù)組,傳入要去重的數(shù)組,遍歷該數(shù)組,若值不在新數(shù)組中則加入該數(shù)組需要注意點判斷值是否在數(shù)組的方法是方法,以下不支持,示例如下對象鍵值對法思路新建一對象以及數(shù)組,遍歷傳入 數(shù)組去重的幾種方法 1.遍歷數(shù)組法 這是最簡單的數(shù)組去重方法,實現(xiàn)思路:新建一新數(shù)組,傳入要去重的數(shù)組,遍歷該數(shù)組,若值不在新數(shù)組中則加入該數(shù)組;...
摘要:方式使用獲取并刪除刪除數(shù)組的第一個元素,判斷這個元素是否還存在于數(shù)組中,如果存在則說明這個元素的是重復的如果不存在,進行操作方式建立一個哈希表,通過對象屬性查詢?nèi)コ貜驮胤绞剿悸泛头绞筋愃?,但是簡潔很多來源個人博客 方式1:使用shift()獲取并刪除刪除數(shù)組的第一個元素,判斷這個元素是否還存在于數(shù)組中,如果存在則說明這個元素的是重復的;如果不存在,進行push()操作 functi...
摘要:專題系列第三篇,講解各種數(shù)組去重方法,并且跟著寫一個前言數(shù)組去重方法老生常談,既然是常談,我也來談?wù)?。它類似于?shù)組,但是成員的值都是唯一的,沒有重復的值。 JavaScript 專題系列第三篇,講解各種數(shù)組去重方法,并且跟著 underscore 寫一個 unique API 前言 數(shù)組去重方法老生常談,既然是常談,我也來談?wù)劇?雙層循環(huán) 也許我們首先想到的是使用 indexOf 來循...
閱讀 1640·2021-10-25 09:46
閱讀 3235·2021-10-08 10:04
閱讀 2383·2021-09-06 15:00
閱讀 2784·2021-08-19 10:57
閱讀 2088·2019-08-30 11:03
閱讀 989·2019-08-30 11:00
閱讀 2389·2019-08-26 17:10
閱讀 3559·2019-08-26 13:36