前端面試手寫代碼——JS數(shù)組去重

1 測試用例

// 測試用例
const a = {};
const b = { c: 1 };
const array = [
  1, 1, "1", "1",
  {}, {}, { c: 1 }, { c: 1},
  a, a, b, b, 
  [], [], [1], [1],
  undefined, undefined,
  null, null,
  NaN, NaN,
];

2 JS 數(shù)組去重4大類型

2.1 元素比較型

此類型通過數(shù)組元素之間進行比較來去重

2.1.1 雙層 for 循環(huán)逐一比較(es5常用)

使用雙層for循環(huán)逐一比較數(shù)組元素,用splice方法去除重復的元素

// 雙層for循環(huán)
function uniq1(arr) {
    for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[i] === arr[j]) {
                arr.splice(j, 1)
                j--
            }
        }
    }
    return arr
}

// 去重結果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN,NaN]

通過對比去重前后結果具伍,重復的NaN沒有去掉嫂侍,因為NaN === NaNfalse

2.1.2 排序相鄰比較

使用sort()方法對數(shù)組元素進行排序凛篙,然后比較相鄰元素依许,用splice方法去除重復的元素申尼。

function uni2(arr) {
    arr.sort();
    for (let i = 0; i < arr.length - 1; i++) {
        arr[i] === arr[i + 1] && arr.splice(i + 1, 1) && i--;
    }
    return arr;
}

也可以創(chuàng)建新數(shù)組寂曹,將不重復的元素放入新數(shù)組中

function uniq3(arr) {
    arr = arr.sort()
    const newArr = [arr[0]]
    for (let i = 1; i < arr.length; i++) {
        if (arr[i] !== arr[i - 1]) {
            newArr.push(arr[i])
        }
    }
    return newArr
}

// 去重結果
// [[],[],1,'1',[1],[1],NaN,NaN,{},{},{c:1},{c:1},{},{c:1},null,undefined]
  1. 重復的NaN沒有去掉感憾,因為NaN === NaNfalse
  2. sort默認排序順序是將元素轉換為字符串,對象轉換為字符串都是[object Object]境钟,所以sort方法不能對數(shù)組中的對象進行排序锦担,也就有可能無法去除重復的對象,除非重復的對象本就相鄰

2.2 查找元素位置型

此類型通過查找元素第一次出現(xiàn)的位置來去重

2.2.1 indexOf

通過indexOf查找當前元素第一次出現(xiàn)的位置是否為當前位置慨削,若是洞渔,則放入新數(shù)組

function uniq4(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (arr.indexOf(arr[i]) === i) {
            res.push(arr[i])
        }
    }
    return res
}

// 去重結果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null]

同樣套媚,因為NaN === NaNfalse,所以用indexOf查找NaN結果總是-1磁椒,從而在新數(shù)組中不會有NaN

2.2.2 findIndex

通過findIndex查找當前元素第一次出現(xiàn)的位置是否為當前位置堤瘤,若是,則放入新數(shù)組

function uniq5(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (arr.findIndex(item => item === arr[i]) === i) {
            res.push(arr[i])
        }
    }
    return res
}
// 去重結果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null]

同樣衷快,因為NaN === NaNfalse宙橱,所以用findIndex查找NaN結果總是-1,從而在新數(shù)組中不會有NaN

2.3 元素是否存在型

此類型通過判斷在新數(shù)組中是否存在當前元素來去重

2.3.1 includes

includes方法用來判斷一個數(shù)組是否包含一個指定的值

function uniq6(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (!res.includes(arr[i])) {
            res.push(arr[i])
        }
    }
    return res
}
// 去重結果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN]

includes使用零值相等算法來確定是否找到給定的元素蘸拔,所以可以判斷NaN是否在新數(shù)組中存在

2.3.2 some

some方法用來測試數(shù)組中是否至少有1個元素通過了被提供的函數(shù)測試

function uniq7(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (!res.some(item => item === arr[i])) {
            res.push(arr[i])
        }
    }
    return res
}
// 去重結果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN,NaN]

同樣师郑,這里仍舊使用了===來比較元素,因為NaN === NaNfalse调窍,所以新數(shù)組中會有多個NaN

2.4 依托數(shù)據(jù)結構特性

此類型通過ES6提供的數(shù)據(jù)結構Map宝冕、Set本身不可重復特性來去重

2.4.1 Map

ES6提供的Map結構可以用各種類型的值(包括對象)當作鍵,且鍵是唯一的

function uniq8(arr) {
    const map = new Map()
    for (let i = 0; i < arr.length; i++) {
        !map.has(arr[i]) && map.set(arr[i], true)
    }
    return [...map.keys()]
}
// 去重結果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN]

map.has方法對NaN也有效

2.4.2 Set(ES6 最常用)

Set結構的成員的值都是唯一的邓萨,沒有重復的值地梨。

function uniq9(arr) {
    return [...new Set(arr)]
}

// 去重結果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN]

3 補充

  1. 上面所說的方法可以使用不同的Api進行改動,比如使用splice方法去除數(shù)組元素的地方缔恳,我們可以通過filter方法來過濾數(shù)組得到新數(shù)組宝剖;

    再比如includes的方法中不用for循環(huán)遍歷數(shù)組,通過reduce方法來代替等等歉甚。

    總之万细,方法有很多,但是萬變不離其宗

  2. 有些去重方法對NaN無效纸泄,因為NaN === NaNfalse赖钞,如果有需求,可以使用Object.is(NaN, NaN)true來進行修改

  3. 實際應用中聘裁,最常用的方法就是使用Set雪营,也可以使用第三方庫lodash來處理

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市衡便,隨后出現(xiàn)的幾起案子献起,更是在濱河造成了極大的恐慌,老刑警劉巖镣陕,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件征唬,死亡現(xiàn)場離奇詭異,居然都是意外死亡茁彭,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門扶歪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來理肺,“玉大人摄闸,你說我怎么就攤上這事∶萌” “怎么了年枕?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乎完。 經(jīng)常有香客問我熏兄,道長,這世上最難降的妖魔是什么树姨? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任摩桶,我火速辦了婚禮,結果婚禮上帽揪,老公的妹妹穿的比我還像新娘硝清。我一直安慰自己,他們只是感情好转晰,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布芦拿。 她就那樣靜靜地躺著,像睡著了一般查邢。 火紅的嫁衣襯著肌膚如雪蔗崎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天扰藕,我揣著相機與錄音缓苛,去河邊找鬼。 笑死实胸,一個胖子當著我的面吹牛他嫡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播庐完,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼钢属,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了门躯?” 一聲冷哼從身側響起淆党,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎讶凉,沒想到半個月后染乌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡懂讯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年荷憋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片褐望。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡勒庄,死狀恐怖串前,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情实蔽,我是刑警寧澤荡碾,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站局装,受9級特大地震影響坛吁,放射性物質發(fā)生泄漏。R本人自食惡果不足惜铐尚,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一拨脉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧塑径,春花似錦女坑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至誉简,卻和暖如春碉就,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背闷串。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工瓮钥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烹吵。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓碉熄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親肋拔。 傳聞我的和親對象是個殘疾皇子锈津,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容