Skip to content

获取JavaScript数组中的所有唯一值并删除重复项

在JavaScript中从数组中删除重复项可以通过多种方式实现,例如使用Array.prototype.reduce()Array.prototype.filter()甚至是简单的for循环。但是,有一种更简单的方法,使用内置的Set对象。

获取数组中的所有唯一值

Set不能包含重复值,并且可以很容易地从数组的值初始化。然后,由于它本身是可迭代的,我们可以使用扩展运算符(...)将其转换回仅包含唯一值的数组。

const uniqueElements = arr => [...new Set(arr)];

uniqueElements([1, 2, 2, 3, 4, 4, 5]); // [1, 2, 3, 4, 5]

检查数组是否包含重复项

Set没有length属性,但它有一个size属性。我们可以使用这个属性来检查数组是否包含重复项。

const hasDuplicates = arr => arr.length !== new Set(arr).size;

hasDuplicates([1, 2, 2, 3, 4, 4, 5]); // true
hasDuplicates([1, 2, 3, 4, 5]); // false

反转条件,我们可以检查数组的所有值是否都是不同的。

const allDistinct = arr => arr.length === new Set(arr).size;

allDistinct([1, 2, 2, 3, 4, 4, 5]); // false
allDistinct([1, 2, 3, 4, 5]); // true

删除出现多次的数组值

如果我们只想保留不重复的值,可以使用Array.prototype.filter()方法。出现多次的元素必须在至少两个不同的索引中出现,因此我们可以使用Array.prototype.indexOf()Array.prototype.lastIndexOf()来检查。如果我们预计数组中有许多重复的值,先将其转换为Set可能会提高性能。

const removeNonUnique = arr =>
  [...new Set(arr)].filter(i => arr.indexOf(i) === arr.lastIndexOf(i));

removeNonUnique([1, 2, 2, 3, 4, 4, 5]); // [1, 3, 5]

我们也可以做相反的操作,删除只出现一次的所有值。在这种情况下,两个索引必须相同。请注意,对于这个操作使用Set将从结果中删除重复项。

const removeUnique = arr =>
  [...new Set(arr)].filter(i => arr.indexOf(i) !== arr.lastIndexOf(i));

removeUnique([1, 2, 2, 3, 4, 4, 5]); // [2, 4]

使用函数查找重复项

更复杂的数据,例如对象,无法使用相等比较进行比较,因此我们需要使用一个函数来检查重复项。在这里,Set对象没有太大用处,所以我们可以使用Array.prototype.reduce()Array.prototype.some()手动将唯一值填充到一个新数组中。使用数组方法,我们还可以检查数组是否包含重复项,或者删除出现多次的所有值。

const uniqueElementsBy = (arr, fn) =>
  arr.reduce((acc, v) => {
    if (!acc.some(x => fn(v, x))) acc.push(v);
    return acc;
  }, []);

const hasDuplicatesBy = (arr, fn) =>
  arr.length !== new Set(arr.map(fn)).size;

const removeNonUniqueBy = (arr, fn) =>
  arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j)));

const data = [
  { id: 0, value: 'a' },
  { id: 1, value: 'b' },
  { id: 2, value: 'c' },
  { id: 1, value: 'd' },
  { id: 0, value: 'e' }
];
const idComparator = (a, b) => a.id == b.id;
const idMap = a => a.id;

uniqueElementsBy(data, idComparator);
// [ { id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' } ]
hasDuplicatesBy(data, idMap); // true
removeNonUniqueBy(data, idComparator);  // [ { id: 2, value: 'c' } ]