摘要:將元素作為對象的鍵,默認鍵對應的值為如果對象中沒有這個鍵,則將這個元素放入結(jié)果數(shù)組中去。
前言
數(shù)組去重在日常開發(fā)中的使用頻率還是較高的,也是網(wǎng)上隨便一抓一大把的話題,所以,我寫這篇文章目的在于歸納和總結(jié),既然很多人都在提的數(shù)組去重,自己到底了解多少呢。又或者是如果自己在開發(fā)中遇到了去重的需求,自己能想到更好的解決方案嗎。
這次我們來理一理怎么做數(shù)組去重才能做得最合適,既要考慮兼容性,也要考慮性能和代碼的優(yōu)雅。
我的學習路徑是模仿冴羽(github: mqyqingfeng)的學習方式,感謝像冴羽這樣優(yōu)秀的人在前面領跑,我不想光看不做,所以多實踐多輸出,希望未來能走出我自己的路。
一、入門方案function unique(origin) { var result = []; for(var i = 0; i < origin.length; i++) { var arrayItem = origin[i]; for(var j= 0; j< result.length; j++) { var resultItem = result[j]; // 如果在結(jié)果數(shù)組循環(huán)中找到了該元素,則跳出循環(huán),進入下一個源數(shù)組元素的判斷 if(resultItem === arrayItem) { break; } } // 如果把結(jié)果數(shù)組循環(huán)完都沒有找到該元素,就將該元素壓入結(jié)果數(shù)組中 if(j === result.length) { result.push(arrayItem); } } return result; } var array = ["a", "b", "c", "1", 0, "c", 1, "", 1, 0]; console.log(unique(array)); // ["a", "b", "c", "1", 0, 1, ""]
以上代碼是最簡單實現(xiàn)數(shù)組去重的方式,優(yōu)點在于兼容性極好,缺點就是兩次 for 循環(huán),時間復雜度為 O(n^2),性能較差。
二、數(shù)組的 indexOf 屬性數(shù)組中的 indexOf 屬性是 ES5 的規(guī)范,只有 IE8 及更早版本不支持該方法。相對來說,如果你不需要兼容 IE8 的話,盡量用 indexOf 來判斷一個元素是否在數(shù)組中。
function unique(origin){ var result = []; for(var i = 0; i< origin.length; i++) { var item = origin[i]; if(result.indexOf(item) === -1) { result.push(item); } } return result; }三、數(shù)組的 filter 屬性
數(shù)組的 filter() 方法創(chuàng)建一個新的數(shù)組,新數(shù)組中的元素是通過檢查指定數(shù)組中符合條件的所有元素。
filter 的回調(diào)有三個參數(shù),其中第三個參數(shù)是當前元素屬于的數(shù)組對象,這樣我們可以繼續(xù)利用 indexOf 屬性啦。
function unique(origin) { var result = origin.filter(function (item, index, array){ // 獲取元素在源數(shù)組的位置,只返回那些索引等于當前元素索引的值。 return array.indexOf(item) === index; }); return result; }
filter 兼容到 IE9, 這種方法沒有 for 循環(huán),主要利用了 filter 和 indexOf 屬性,所以代碼相對比較優(yōu)雅。
四、利用 Object 的 key valuefunction unique(origin) { var result = []; var hashTable = {}; for(var i = 0; i< origin.length; i++) { // 如果鍵對應的值,為真,意味著對象的鍵中已經(jīng)有重復的鍵了。 if(!hashTable[origin[i]]) { // 將元素作為對象的鍵,默認鍵對應的值為 true, hashTable[origin[i]] = true; // 如果對象中沒有這個鍵,則將這個元素放入結(jié)果數(shù)組中去。 result.push(origin[i]); } } return result; }
這種方案的事件復雜度為 O(n), 但是對象的鍵,默認是字符串類型,這意味著什么呢,數(shù)字 1 和 字符串 "1",在鍵中是相等的,所以,上面這種方法不適合字符串和數(shù)字混合的去重。
所以我們將元素的類型也放入對象的鍵中:
function unique(origin) { var result = []; var hashTable = {}; for(var i = 0; i< origin.length; i++) { var current = origin[i]; // 字符串拼接元素的類型和元素 var key = typeof(current) + current; if(!hashTable[key]) { hashTable[key] = true; result.push(current); } } return result; }五、數(shù)組的 sort 方法
function unique(origin) { return origin.concat.sort().filter(function(item, index, array) { // !index 表示第 0 個元素應該被返回。 return !index || item !== origin[index-1] }) } function unique(array) { array.sort(); // 排序字符串 array.sort(function(a, b) { return a-b; // 排序數(shù)字 }) for(let i=0; isort 方法的優(yōu)點在于利用了排序,返回后一個和前一個不相等的元素。比較簡潔和直觀。缺點在于改變了元素的本來的排序位置。
六、ES6 SetES6 提供了新的數(shù)據(jù)結(jié)構(gòu) Set,它類似于數(shù)組,但是成員的值都是唯一的,沒有重復的值。向 Set 加入值的時候,不會發(fā)生類型轉(zhuǎn)變,所以 5 和 "5" 是兩個不同的值。Set內(nèi)部判斷兩個值是否相同,用的是類似于 "==="的算法,但是區(qū)別是,在set內(nèi)部認為NaN 等于 NaN ;
Set 可以轉(zhuǎn)換為數(shù)組,所以很容易實現(xiàn)去重
function unique(origin) { return Array.from(new Set(origin)); }七、ES6 MapES6 新增了 Map 數(shù)據(jù)結(jié)果,通過 has 和 set 方法就能很方便的對前面的 object key value 方案進行優(yōu)化。
function unique(origin){ const map = new Map() return origin.filter((item) => !map.has(item) && map.set(item, true)) }八、類型判斷一些常見的數(shù)據(jù)類型是 === 和 indexOf 是無法檢測的,舉個例子:
console.log({} === {}) // false; console.log(NaN === NaN) // false; console.log(/a/ === /a/); // false; console.log(1 === new String("1")) // false; var arr = [NaN]; console.log(arr.indexOf(NaN)); // -1所以在判斷的時候,如果數(shù)據(jù)里有 NaN 和對象時要避免使用 indexOf 和 ===;
前面 Set 那里說過了,所以 Set 方法是可以去重 NaN的。
總結(jié)數(shù)據(jù)去重在網(wǎng)上已經(jīng)看煩了,但還是想專門寫一篇文章來實踐和總結(jié),能在工作中多幾個思路也是極好的。感謝那些熱愛分享和喜歡輸出的人。
歡迎關(guān)注我的個人公眾號“謝南波”,專注分享原創(chuàng)文章。
掘金專欄 JavaScript 系列文章JavaScript之變量及作用域
JavaScript之聲明提升
JavaScript之執(zhí)行上下文
JavaScript之變量對象
JavaScript之原型與原型鏈
JavaScript之作用域鏈
JavaScript之閉包
JavaScript之this
JavaScript之a(chǎn)rguments
JavaScript之按值傳遞
JavaScript之例題中徹底理解this
JavaScript專題之模擬實現(xiàn)call和apply
JavaScript專題之模擬實現(xiàn)bind
JavaScript專題之模擬實現(xiàn)new
JS專題之事件模型
JS專題之事件循環(huán)
JS專題之去抖函數(shù)
JS專題之節(jié)流函數(shù)
JS專題之函數(shù)柯里化
JS專題之數(shù)組去重
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/108916.html
摘要:根據(jù)需求的特點,數(shù)組展開需要進行迭代和遞歸?;卮鹞恼麻_頭的問題將多重數(shù)組轉(zhuǎn)化成單層數(shù)組的過程就是數(shù)組展開,也叫作數(shù)組扁平化一循環(huán)加遞歸最簡單的思路循環(huán)中判斷,如果子元素是數(shù)組則遞歸。 前言 首先什么是數(shù)組展開? 假如現(xiàn)在有這樣一個需求:將后臺的一個多重 List 數(shù)據(jù),展開成一個 List 后,并去重后排序; [a, b, [c, d], [[d],e], f] => [a, b, ...
摘要:專題系列共計篇,主要研究日常開發(fā)中一些功能點的實現(xiàn),比如防抖節(jié)流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點是研究專題之函數(shù)組合專題系列第十六篇,講解函數(shù)組合,并且使用柯里化和函數(shù)組合實現(xiàn)模式需求我們需要寫一個函數(shù),輸入,返回。 JavaScript 專題之從零實現(xiàn) jQuery 的 extend JavaScritp 專題系列第七篇,講解如何從零實現(xiàn)一個 jQuery 的 ext...
距離上次發(fā)文,已經(jīng)有一段時間了,最近工作比較忙,這不眼看快雙十一了,就相當于給大家一些福利吧! showImg(https://segmentfault.com/img/remote/1460000016538082?w=250&h=250); 一、什么是數(shù)組去重 簡單說就是把數(shù)組中重復的項刪除掉,你 GET 到了嗎 ?下面我將簡單介紹下幾種基本的方法及其優(yōu)缺點。 二、方法匯總 兩層循環(huán) 無相同...
摘要:寫在前面專題系列是我寫的第二個系列,第一個系列是深入系列。專題系列自月日發(fā)布第一篇文章,到月日發(fā)布最后一篇,感謝各位朋友的收藏點贊,鼓勵指正。 寫在前面 JavaScript 專題系列是我寫的第二個系列,第一個系列是 JavaScript 深入系列。 JavaScript 專題系列共計 20 篇,主要研究日常開發(fā)中一些功能點的實現(xiàn),比如防抖、節(jié)流、去重、類型判斷、拷貝、最值、扁平、柯里...
摘要:專題系列第三篇,講解各種數(shù)組去重方法,并且跟著寫一個前言數(shù)組去重方法老生常談,既然是常談,我也來談談。它類似于數(shù)組,但是成員的值都是唯一的,沒有重復的值。 JavaScript 專題系列第三篇,講解各種數(shù)組去重方法,并且跟著 underscore 寫一個 unique API 前言 數(shù)組去重方法老生常談,既然是常談,我也來談談。 雙層循環(huán) 也許我們首先想到的是使用 indexOf 來循...
閱讀 2674·2021-11-25 09:43
閱讀 1923·2021-09-22 15:26
閱讀 3956·2019-08-30 15:56
閱讀 1790·2019-08-30 15:55
閱讀 1959·2019-08-30 15:54
閱讀 875·2019-08-30 15:52
閱讀 3231·2019-08-29 16:23
閱讀 971·2019-08-29 12:43