JavaScript 中数组删除重复项

Posted by cl9000 on June 20, 2020

不畏惧失败是创造力的一个基本要素。——<艾尔文·兰德博士>

作者:Ashish Lahoti
译者:cl9000
来源:https://codingnconcepts.com/javascript/how-to-remove-array-duplicates-in-javascript/

在本教程中,我们将学习如何从 JavaScript 中的数组中删除重复项并仅返回唯一值。

这是从数组中删除重复项的不同方法的快速视图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Array:
const fruits = ['apple', 'orange', 'orange', 'apple', 'banana', 'apple'];

// 1. ES6 Set
[...new Set(fruits)];

// 2. filter
fruits.filter((item, index) => fruits.indexOf(item) == index);

// 3. forEach
fruits.forEach(item => !uniqueFruits.includes(item) && uniqueFruits.push(item));

// 4. reduce
fruits.reduce((newarray, item) => newarray.includes(item) ? newarray : [...newarray, item], []);

// Result:
// ▶ Set(3) {"apple", "orange", "banana"}

1. 使用 ES6 的 Set()

如果你已经开始使用ES6,那么建议使用Set对象。

Set对象允许您存储任何类型的唯一值,无论是原始值还是对象引用。
当你将一个数组传递给新的 Set() 对象时,它会删除任何重复的值。让我们看看代码中发生了两件事:

  • 首先,我们通过传递一个数组来创建一个新的 Set对象,该数组删除了重复项。
  • 其次,我们使用 spread operator… 将该对象转换回一个数组。
1
2
3
4
5
6
7
const fruits = ['apple', 'orange', 'orange', 'apple', 'banana', 'apple'];

const uniqueSet = new Set(fruits);
// ▶ Set(3) {"apple", "orange", "banana"}

const backToArray = [...uniqueSet];
// ▶ (3) ["apple", "orange", "banana"]

另外,您也可以使用 Array.from 将转换 Set 为数组:

1
2
3
4
const fruits = ['apple', 'orange', 'orange', 'apple', 'banana', 'apple'];

const uniqueFruits = Array.from(new Set(fruits));
// ▶ Set(3) {"apple", "orange", "banana"}

2. 使用 Array.filter()

filter() 方法根据我们提供的条件从数组中滤除元素。换句话说,

  • 如果条件返回true,它将包含在过滤后的数组中
  • 如果条件返回false,则不会将其包含在过滤后的数组中
1
2
3
4
const fruits = ['apple', 'orange', 'orange', 'apple', 'banana', 'apple'];

const uniqueFruits = fruits.filter((item, index) => fruits.indexOf(item) == index);
// ▶ Set(3) {"apple", "orange", "banana"}

在这里,Array.indexOf() 方法的使用非常重要,如果有重复的话,它可以使您第一次出现元素。让我们看一下代码:

1
2
3
4
const fruits = ['apple', 'orange', 'orange', 'apple', 'banana', 'apple'];
fruits.indexOf('apple'); //0
fruits.indexOf('orange'); //1
fruits.indexOf('banana'); //4

3. 使用 Array.forEach()

forEach() 方法还可以用于循环遍历数组中的元素,并将元素push()到新数组中,但新数组中并不存在。

1
2
3
4
5
6
7
 const fruits = ['apple', 'orange', 'orange', 'apple', 'banana', 'apple'];

const uniqueFruits = [];
fruits.forEach(item => !uniqueFruits.includes(item) && uniqueFruits.push(item));

console.log(uniqueFruits);
// ▶ Set(3) {"apple", "orange", "banana"}

4. 使用 Array.reduce()

reduce()方法用于减少数组的元素,并根据传递的某些reducer函数将它们组合成一个新数组。

在本例中,reducer函数检查新数组是否包含该项。如果没有,则将该项推入新数组。否则,跳过该元素并按原样返回新数组。

Reduce总是有点难以理解。让我们看一下代码:

1
2
3
4
5
6
7
const fruits = ['apple', 'orange', 'orange', 'apple', 'banana', 'apple'];

const uniqueFruits =
fruits.reduce((newarray, item) => newarray.includes(item) ? newarray : [...newarray, item], []);

console.log(uniqueFruits);
// ▶ Set(3) {"apple", "orange", "banana"}

5. 性能

我们已经创建了一个包含100万个随机数(从1到1000)的数组。让我们检查一下每种方法的性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Array:
var numbers = [];
for ( var i = 0; i < 1000000; i++ ) {
numbers.push(Math.floor((Math.random() * 1000) + 1));
}

// 1. ES6 Set
console.time("set");
[...new Set(numbers)];
console.timeEnd("set");

// 2. filter
console.time("filter");
numbers.filter((item, index) => numbers.indexOf(item) == index);
console.timeEnd("filter");

// 3. forEach
console.time("forEach");
var uniqueNumbers = [];
numbers.forEach(item => !uniqueNumbers.includes(item) && uniqueNumbers.push(item));
console.timeEnd("forEach");

// 4. reduce
console.time("reduce");
numbers.reduce((newarray, item) => newarray.includes(item) ? newarray : [...newarray, item], []);
console.timeEnd("reduce");

这里是我在MacBook Pro的Chrome v83.0.4103.106(64位)上运行上述代码的结果:

1
2
3
4
set:      23.051025390625ms
filter: 1004.9609375ms
forEach: 471.6630859375ms
reduce: 472.902099609375ms

我们看到 ES6 Set对象是一个明显的赢家,后面跟着forEach循环。强烈建议使用ES6 Set从数组中删除重复项,因为它的语法简洁,性能也很好。

参考

关注【公众号】,了解更多。
关注【公众号】,了解更多。
关注【公众号】,了解更多。



支付宝打赏 微信打赏

赞赏一下 坚持原创技术分享,您的支持将鼓励我继续创作!