JavaScript實現(xiàn)數(shù)組去重的20種方法總結
1.easy模式
此時我們有一個極其簡單的數(shù)組,它可能包含也不包含重復項。我們需要刪除重復項并將唯一值放入新數(shù)組中。
const names = ["a","b","c","d","e","a","b"];
new Set
時間復雜度:O(n^2), 但擴展符運算符耗費時間有點多,一般推薦
最簡單的,new Set去重
let newNames = [...new Set(names)]
時間復雜度:O(n^2), 比擴展運算符還費勁,一般推薦
let newNames = Array.from(new Set(names))
new Map
時間復雜度:O(n^2), 一般推薦 通過new Map原型上的方法去重。
function dealArr (a) { let newArr = [] let map = new Map() for(let i = 0;i<a.length;i++){ if (!map.has(a[i])) { map.set(a[i], true) newArr.push(a[i]) } }; return newArr }
笨蛋雙重for循壞
感覺實在沒什么好說的,就純暴力去重
function dealArr(a){ let len = a.length; for(let i = 0; i < len; i++) for(let j = i + 1; j < len; j++) if(a[j] == a[i]){ a.splice(j,1); j--; len--; } return a; }
function dealArr(a) { let b = []; for (let i = a.length - 1; i >= 0; i--) { for (let j = a.length - 1; j >= 0; j--) { if (a[i] == a[j] && i != j) { delete a[j]; } } if (a[i] != undefined) b.push(a[i]); } return b; }
單for循壞
時間復雜度:O(n), 它真的太快了,它是所有種類的方法里最快的,大伙可以試一試, 推薦
for循壞+hash查找
function dealArr(a) { let obj = {}; let out = []; let len = a.length; let j = 0; for(let i = 0; i < len; i++) { let item = a[i]; if(obj[item] !== 1) { obj[item] = 1; out[j++] = item; } } return out; }
下面這種會快一點。
function dealArr(a) { obj = {}; for (let i = 0; i < a.length; i++) { obj[a[i]] = true; } return Object.keys(obj); }
for and includes
時間復雜度:O(n^2), 不推薦
for循環(huán) + includes判斷,includes會循壞到找到為止或者全部,所以挺慢的。
function dealArr(a) { let newArr = []; let j = 0; for (i = 0; i < a.length; i++) { let current = a[i]; if (!newArr.includes(current)) newArr[j++] = current; } return newArr; }
for and indexOf
時間復雜度:O(n^2), 不推薦
for循環(huán) + indexof查找,indexOf會找到第一個為止或者全部。
function dealArr(a) { let newArr = []; let j = 0; for (i = 0; i < a.length; i++) { let current = a[i]; if (newArr.indexOf(current) < 0) newArr[j++] = current; } return newArr; }
for and lastIndexOf
時間復雜度:O(n^2), 不推薦
沒啥好說的,其實和indexOf一樣只是正反序查找的區(qū)別而已,問就是慢
function dealArr(a) { let newArr = []; let j = 0; for (i = 0; i < a.length; i++) { let current = a[i]; if (newArr.lastIndexOf(current) < 0) newArr[j++] = current; } return newArr; }
for and newArr
相比哈希也慢
一個新數(shù)組和原數(shù)組對比,不同則放在新數(shù)組,最后返回。
function dealArr(a) { let newArr = [a[0]]; for (let i = 1; i < a.length; i++) { let repeat = false; for (let j = 0; j < newArr.length; j++) { if (a[i] === newArr[j]) { repeat = true; break; } } if (!repeat) { newArr.push(a[i]); } } return newArr; }
for and sort
想想有什么問題
先將原數(shù)組排序,再與相鄰的進行比較,如果不同則存入新數(shù)組。
function dealArr(a) { let formArr = a.sort() let newArr=[formArr[0]] for (let i = 1; i < formArr.length; i++) { if (formArr[i]!==formArr[i-1]) newArr.push(formArr[i]) } return newArr }
splice
O(n^2),特別慢
function dealArr(arr) { let i,j,len = arr.length; for (i = 0; i < len; i++) { for (j = i + 1; j < len; j++) { if (arr[i] == arr[j]) { arr.splice(j, 1); len--; j--; } } } return arr; }
filter and indexOf
時間復雜度:O(n^2)一般推薦
filter的本質相當于,在每一個元素上添加檢查,檢查該元素在數(shù)組中的第一個位置是否等于當前位置,indexof是找到第一個符合條件的元素。重復元素在數(shù)組里的位置是與找到的第一個不同的。
let newNames = names.filter(function(item, index) { return names.indexOf(item) == index; })
但其實上述方法不是很好,因為可能你會操作到原數(shù)組,導致原數(shù)據(jù)變化,那么我們可以直接用filter的第三個參數(shù)來做這件事,保證原數(shù)據(jù)的不可變性。
let newNames = names.filter(function(item, index, self) { return self.indexOf(item) == index; })
filter and sort
時間復雜度:O(n)- O(n^2)不推薦
就是先對數(shù)組進行排序,然后刪除與前一個元素相等的每個元素。大家也可以想想這方法有啥問題。提示:排序。
let newNames = a.sort().filter(function(item, index, self) { return !index || item != self[index - 1]; });
reduce
實在是太慢了,不推薦
reduce果然是js里最完美的api。
let newNames = names.reduce(function(a,b){ if (a.indexOf(b) < 0 ) a.push(b); return a; },[]);
笨蛋hashMap
時間復雜度:O(n)一般
這個方法有點笨,通過哈希表查找來fiter,大伙可以想一想缺陷是什么。(提示:對象,key。 測試用例: [1, '1']。)
function dealArr(a) { let seen = {}; return a.filter(function(item) { return seen.hasOwnProperty(item) ? false : (seen[item] = true); }); }
2.Normal模式
easy模式下我們都只處理一些基數(shù)組,接下來我們處理一下數(shù)組對象+基數(shù)組。
一般聰明的hashMap
一般聰明的hash,大伙看到這應該能明白上面的問題是什么了吧。經過一點點優(yōu)化,我們對原始值和引用對象分開處理,到這它已經有了處理對象引用重復的能力了,但是它確實還不夠聰明。
就像這樣:
function dealArr(a) { let prims = {"boolean":{}, "number":{}, "string":{}}, objs = []; return a.filter(function(item) { let type = typeof item; if(type in prims) return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true); else return objs.indexOf(item) >= 0 ? false : objs.push(item); }); }
聰明的hashMap
我們有時候可以寫一個通用的函數(shù),通過回調函數(shù)來優(yōu)雅的完成過濾,比如這樣!
大家可以思考一下為什么JSON.stringify,能完成過濾。
function dealArrByBey(a, key) { let obj = {}; return a.filter(function(item) { let k = key(item); return obj.hasOwnProperty(k) ? false : (obj[k] = true); }) }
稍微炫一點
但這都es6了還這么玩不太合適,這樣會好看一些。
可以看到過濾了后面的b.
function dealArrByBey(a, key) { let obj = new Set(); return a.filter(item => { let k = key(item); return obj.has(k) ? false : obj.add(k); }); }
特別炫
感覺這么寫就特別開心了,雖然可讀性不好,而且也不是很快,但它很帥啊。但這三種方法,是有點區(qū)別的,上面兩種方法是保留第一個,過濾掉后面的,而這種方法保留的是最后一個,大伙可以思考一下為什么。
function dealArrByBey(a, key) { return [ ...new Map( a.map(x => [key(x), x]) ).values() ] }
3.hard模式
珂里化 + 鏈式調用
em,都寫到這了,我們可以再進階再抽象一下,讓我們的去重也可以寫成一個非常抽象的鏈式調用。多重箭頭函數(shù)其實就是函數(shù)珂里化的語法糖(fn(a,b,c)改造成fn(a)(b)(c)),讓我們完成一個參數(shù)對齊。
const apply = f => a => f(a); const flip = f => b => a => f(a) (b); const uncurry = f => (a, b) => f(a) (b); const push = x => xs => (xs.push(x), xs); const fold = f => acc => xs => xs.reduce(uncurry(f), acc); const some = f => xs => xs.some(apply(f)); const dealArrByFn = f => fold( acc => x => some(f(x)) (acc) ? acc : push(x) (acc) ) ([]); const eq = y => x => x === y; dealArrByFn(eq)(names)
到此這篇關于JavaScript實現(xiàn)數(shù)組去重的20種方法總結的文章就介紹到這了,更多相關JavaScript數(shù)組去重內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Javascript前端UI框架Kit使用指南之kitjs的對話框組件
本文以kitjs對話框組件為例,給我們詳細介紹了kitjs的組件目錄、默認代碼模板、構造器及初始方法、以及Kitjs繼承。講解的非常細致,對我們熟練掌握kitjs組件很有幫助。2014-11-11javascript showModalDialog模態(tài)對話框使用說明
使用javascript打開模態(tài)對話框,想學習showModalDialog使用方法的朋友可以參考下。2009-12-12JavaScript實現(xiàn)一個簡易的計算器實例代碼
這篇文章主要介紹了JavaScript實現(xiàn)一個簡易的計算器實例代碼,具有很好的參考價值,希望對大家有所幫助,一起跟隨小編過來看看吧2018-05-05