來一個老生長談的話題,Javascript 中,數組如何去重?

關於如何去除一個給定數組中的重複項,應該是 Javascript 面試中最常見的一個問題了,最常見的方式有三種:SetArray.prototype.filter 以及 Array.prototype.reduce,對於只有簡單數據的數組來講,我最喜歡 Set,沒別的,就是寫起來簡單。

const originalArray = [1, 2, '咩', 1, 'Super Ball', '咩', '咩', 'Super Ball', 4]

const bySet = [...new Set(originalArray)]

const byFilter = originalArray.filter((item, index) => originalArray.indexOf(item) === index)

const byReduce = originalArray.reduce((unique, item) => unique.includes(item) ? unique : [...unique, item], [])

使用 Set

先讓我們來看看 Set 到底是個啥

Set 對象允許你存儲任何類型的唯一值,無論是原始值或者是對象引用。

<cite>https://developer.mozilla.org...</cite>

  • 首先,Set 中只允許出現唯一值
  • 唯一性是比對原始值或者對象引用

const bySet = [...new Set(originalArray)] 這一段的操作,我們將它拆分來看:

const originalArray = [1, 2, '咩', 1, 'Super Ball', '咩', '咩', 'Super Ball', 4]

const uniqueSet = new Set(originalArray)
// 得到 Set(5) [ 1, 2, "咩", "Super Ball", 4 ]

const bySet = [...uniqueSet]
// 得到 Array(5) [ 1, 2, "咩", "Super Ball", 4 ]

在將 Set 轉爲 Array 時,也可以使用 Array.from(set)

使用 Array.prototype.filter

要理解 filter 方法爲什麼可以去重,需要關注一下另一個方法 indexOf

indexOf()方法返回在數組中可以找到一個給定元素的第一個索引,如果不存在,則返回 -1

<cite>https://developer.mozilla.org...</cite>

const beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];

console.log(beasts.indexOf('bison'));
// expected output: 1

// start from index 2
console.log(beasts.indexOf('bison', 2));
// expected output: 4

console.log(beasts.indexOf('giraffe'));
// expected output: -1
filter() 方法創建一個新數組, 其包含通過所提供函數實現的測試的所有元素。

<cite>https://developer.mozilla.org...</cite>

filter 方法接受兩個參數:

  • 第一個參數:一個回調函數, filter 會將數據中的每一項都傳遞給該函數,若該函數返回 真值,則數據保存,返回 假值,則數據將不會出現在新生成的數據中
  • 第二個參數:回調函數中 this 的指向

我們將上面的去重方法按下面這樣重寫一下,就可以看清整個 filter 的執行過程了。

const originalArray = [1, 2, '咩', 1, 'Super Ball', '咩', '咩', 'Super Ball', 4]

const table = []

const byFilter = originalArray.filter((item, index) => {
  // 如果找到的索引與當前索引一致,則保留該值
  const shouldKeep = originalArray.indexOf(item) === index
  table.push({
    序號: index,
    值: item,
    是否應該保留: shouldKeep ? '保留' : '刪除'
  })
  return shouldKeep
})

console.log(byFilter)
console.table(table)
序號 是否應該保留 -
0 1 保留 第一次出現
1 2 保留 第一次出現
2 保存 第一次出現
3 1 刪除 第二次出現
4 Super Ball 保留 第一次出現
5 刪除 第二次出現
6 刪除 第三次出現
7 Super Ball 刪除 第二次出現
8 4 保留 第一次出現

使用 Array.prototype.reduce

reduce() 方法對數組中的每個元素執行一個由您提供的 reducer 函數(升序執行),將其結果彙總爲單個返回值。

<cite>https://developer.mozilla.org...</cite>

Array.prototype.reduce 方法接受兩個參數:

  • Callback:回調函數,它可以接收四個參數

    • Accumulator:累計器,這個其實是讓很多人忽略的一點,就是,累計器其實可以是任何類型的數據
    • Current Value:當前值
    • Current Index:當前值的索引
    • Source Array:源數組
  • Initial Value:累計器的初始值,就跟累計器一樣,這個參數也總是被絕大多數人忽略

就像 filter 章節一樣,我們來看看 reduce 的執行過程:

const originalArray = [1, 2, '咩', 1, 'Super Ball', '咩', '咩', 'Super Ball', 4]

const byReduce = originalArray.reduce((unique, item, index, source) => {
  const exist = unique.includes(item)
  const next = unique.includes(item) ? unique : [...unique, item]
  console.group(`遍歷第 ${index} 個值`)
  console.log('當前累計器:', unique)
  console.log('當前值:', item)
  console.log('是否已添加進累計器?', exist)
  console.log('新值', next)
  console.groupEnd()
  return next
}, [])
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章