JavaScript:如何从数组中删除重复值
原文发布于威尔的博客
在之前的文章中,我们了解了如何判断 JavaScript 数组中是否包含重复值。今天,我想介绍几种从数组中删除重复值的方法。
使用Array.prototype.filter()&Array.prototype.indexOf()方法
let originalArray = [1, 2, 3, 4, 1, 2, 3, 4]
let uniqueArray = originalArray.filter((item, index, array) => {
return array.indexOf(item) === index
})
// uniqueArray === [1, 2, 3, 4]
这里的基本策略是遍历originalArray并检查当前正在检查的项的索引是否与表中项的索引相同originalArray。
因为indexOf该函数返回的是给定值找到的第一个索引,如果不是重复值,则该项的索引必须相同!
请注意,这种方法并非最高效:它的执行时间为二次方级。因此,如果您要检查的数组非常大,则可能需要使用其他方法。
另一个值得注意的地方是,我们可以通过反转比较结果,使用相同的方法只返回重复值:
let duplicateArray = originalArray.filter((item, index, array) => {
return array.indexOf(item) !== index
})
使用Array.prototype.reduce()&Array.prototype.includes()
let originalArray = [1, 2, 3, 4, 1, 2, 3, 4]
let uniqueArray = originalArray.reduce((unique, item) => {
unique.includes(item) ? unique : [...unique, item]
}, [])
// uniqueArray === [1, 2, 3, 4]
这里的策略是在 reducer 函数的“累加器”中维护一个唯一项的列表unique。对于列表中的每个项,originalArray我们检查累加器中是否包含该项。
- 如果它确实包含该项,则返回累加器而不做任何更改,实际上是“跳过”该项。
- 如果累加器中不包含该项,则将累加器中的值展开到一个新数组中,然后添加要考虑的项。
Array.prototype.includes返回一个布尔值——true如果该值存在于数组中,则返回 true;false否则返回 false。这个布尔值决定了我们的条件判断,进而决定如何处理每个值。
我觉得这种方法不太直观,也比较难读,但它确实有效。
另请注意,reducer 函数之后传入的空数组是累加器的起始值,因此第一次经过累加器时reduce,unique数组为空。
⚡ 使用 ES6Set对象 ⚡
let originalArray = [1, 2, 3, 4, 1, 2, 3, 4]
let uniqueArray = array => [...new Set(array)]
// or
let uniqueArray = Array.from(new Set(originalArray))
// uniqueArray = [1, 2, 3, 4]
Set这种方法利用了ES6 中引入的对象的功能。
集合保证保留插入元素的顺序,并且只包含唯一值。因此,根据定义,集合不可能包含重复项!
这里我们调用Set对象的构造函数,并将要从中构造对象的数组作为参数传递给它Set。然后,在去除所有重复项并将剩余值存储在对象中之后Set,我们将其转换回数组并返回结果。
我看到一些讨论指出,如果处理的数组非常大且包含大量重复值,这种方法的性能会略有下降。然而,同样的讨论也指出,在数据重复值很少的情况下,这种方法非常高效。
我个人认为,最后这种方法的简洁性足以构成使用Set面向对象方法的理由,除非有令人信服的性能原因不这样做。