J 筆記 - Remove Array Dup

J 筆記 - ES6 Remove Array Duplicates

在 Ruby 裡面要做這件事情真的方便許多直接 uniq 就可以完成,但常常被寫好的 method 慣壞了卻想不太到 JS 裡頭該怎麼實作,所以整理一些 Remove Array Duplicates 的方法…

3 ways in ES6

總共在 ES6 裡面有 3 種方法可以實作,而我最喜歡的莫過於 Set,又短又不用想到底裡面做了什麼,不像 filterreduce,另外也覺得有點像 Ruby 的 uniq,所以寫起來快速又實用~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const array = ['Remove', 'Remove', 'ES5', 'ES6', 'Remove', 'ES7'];

// 1: "Set"
[...new Set(array)];

// 2: "Filter"
array.filter((item, index) => array.indexOf(item) === index);

// 3: "Reduce"
array.reduce((uniq, item) =>
uniq.includes(item) ? uniq : [...uniq, item], []);

// RESULT:
// ['Remove', 'ES5', 'ES6', 'ES7']

1. Set

The Set object lets you store unique values of any type, whether primitive values or object references.

ES6 提供了新的數據結構 Set。它類似於數組,但值都是唯一的,没有重複的值。

因此我們來看看到底做了什麼…

1
2
3
4
5
6
7
const array = ['Remove', 'Remove', 'ES5', 'ES6', 'Remove', 'ES7'];

const newarray = new Set(array);

console.log(newarray);
// RESULT:
// Set(4) {"Remove", "ES5", "ES6", "ES7"}

在結合之前前幾篇的 spread operatorArray.from 將它變成陣列

1
2
3
4
5
6
7
const array = ['Remove', 'Remove', 'ES5', 'ES6', 'Remove', 'ES7'];

const newarray = new Set(array);
const backToArray = [...newarray];
const ArrayfromtoArray = Array.from(newarray);
// RESULT:
// Set(4) ["Remove", "ES5", "ES6", "ES7"]

2. filter

1
2
3
4
const array = ['Remove', 'Remove', 'ES5', 'ES6', 'Remove', 'ES7'];

// 2: "Filter"
array.filter((item, index) => array.indexOf(item) === index);

雖然這樣子就能出現答案,但中間 Array.prototype.indexOf() 是做了什麼事情呢?

The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.

1
2
3
4
5
6
7
8
9
10
11
12
const array = ['Remove', 'Remove', 'ES5', 'ES6', 'Remove', 'ES7'];

array.filter((item, index) => {
console.log(
item,
index,
array.indexOf(item),
array.indexOf(item) === index,
);

return array.indexOf(item) === index
});
item index indexOf condition
Remove 0 0 True
Remove 1 0 False
ES5 2 2 True
ES6 3 3 True
Remove 4 0 False
ES7 5 5 True

2.x 相反

1
2
3
4
5
6
7
8
9
10
11
12
13
const array = ['Remove', 'Remove', 'ES5', 'ES6', 'Remove', 'ES7'];

array.filter((item, index) => {
console.log(
item,
index,
array.indexOf(item),
array.indexOf(item) === index,
);

return array.indexOf(item) !== index
// ['Remove', 'Remove']
});
item index indexOf condition
Remove 0 0 False
Remove 1 0 True
ES5 2 2 False
ES6 3 3 False
Remove 4 0 True
ES7 5 5 False

3. reduce

1
2
3
4
5
const array = ['Remove', 'Remove', 'ES5', 'ES6', 'Remove', 'ES7'];

// 3: "Reduce"
array.reduce((uniq, item) =>
uniq.includes(item) ? uniq : [...uniq, item], []);

同上,雖然這樣子就能出現答案,但中間 Array.prototype.reduce() 是做了什麼事情呢?

The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.

1
2
3
4
5
6
7
8
9
10
11
12
const array = ['Remove', 'Remove', 'ES5', 'ES6', 'Remove', 'ES7'];

array.reduce((uniq, item) => {
console.log(
item,
uniq,
uniq.includes(item),
uniq.includes(item) ? uniq : [...uniq, item],
);

return uniq.includes(item) ? uniq : [...uniq, item]
}, []);
item Accumulator (BEFORE Reducer Function) Push to Accumulator? Accumulator (AFTER Reducer Function)
Remove [] Yes [‘Remove’]
Remove [‘Remove’] NO [‘Remove’]
ES5 [‘Remove’] Yes [‘Remove’, ‘ES5’]
ES6 [‘Remove’, ‘ES5’] Yes [‘Remove’, ‘ES5’, ‘ES6’]
Remove [‘Remove’, ‘ES5’, ‘ES6’] No [‘Remove’, ‘ES5’, ‘ES6’]
ES7 [‘Remove’, ‘ES5’, ‘ES6’] Yes [‘Remove’, ‘ES5’, ‘ES6’, ‘ES7’]

參考資料