如何在JavaScript中删除数组中的重复内容

153 阅读4分钟

简介

在消费API或从数组中检索数据时,你可能会遇到重复的数据,但你只想选择唯一的值。

例如,假设你有一个代表餐厅菜单的数组,如下图所示。你可能需要从该数组中检索可用的类别--在这种情况下,你需要过滤该数组,只获得一次类别,避免重复。

const menu = [
    {
        name: "buttermilk pancakes",
        category: "breakfast"
    },
    {
        name: "diner double",
        category: "lunch"
    },
    {
        name: "godzilla milkshake",
        category: "dinner"
    },
    {
        name: "country delight",
        category: "breakfast"
    },
    {
        name: "egg attack",
        category: "lunch"
    }
];

在这篇文章中,我们将学习如何在JavaScript中去除数组中的重复部分,基本上是创建一个唯一值的数组。我们将看看几种不同的方法,这样你就能选择最适合你项目的方法。

最好的解决方案。使用*Set()*构造函数

Set是一个项目的集合,它是唯一的,也就是说,没有元素可以重复。假设我们有一个学校科目的数组,我们想从其中删除所有重复的内容。

let subjects = ["mathematics", "french", "english", "french", "mathematics"];

JavaScript为我们提供了一个创建集合的方便的构造函数--Set() 。它可以接受一个数组作为它的参数。在这种情况下,它创建一个集合,并从传递的数组中填充唯一的值。这种方法的问题在于,Set() 构造函数创建的是一个集合,而不是一个数组(我们需要的)。

我们将绕过这个不受欢迎的行为,使用 传播操作符- 也被称为三点运算符(...)。当与一个集合(用Set() 构造函数产生)结合时,传播操作符可以将集合的值传播到一个数组中。

let uniqueSubjects = [...new Set(subjects)];

console.log(uniqueSubjects); // ["mathematics", "french", "english"]

我们也可以对一个对象的数组这样做,让我们在 menu 数组的例子上说明一下。

let categories = [...new Set( menu.map((menu) => menu.category))];

console.log(categories); // ["breakfast","lunch","dinner"]

**注意:**使用Set() 构造函数从一个数组中删除重复的元素需要线性时间--O(n) (n 是原数组中的元素数)。所有其他去除重复的方法都需要O(n²) 。因此,我们强烈建议你在任何可能的情况下使用Set() 构造函数。

使用*filter()indexOf()*方法

filter() 方法用于循环浏览一个数组,并返回一个仅由符合给定条件的元素组成的新数组,而indexOf() 方法用于返回该元素在数组中首次出现的索引。

例如,假设我们有一个主题数组,我们想检查每个元素的索引。

let subjects = ["mathematics", "french", "english", "french", "mathematics"];

let subjectsIndex = [];
subjects.map((subject) => {
    subjectsIndex.push(subjects.indexOf(subject));
});

console.log(subjectsIndex); // [0,1,2,1,0]

因为我们知道过滤器方法根据给定的标准返回一个新的数组,我们现在可以用它来只包括那些索引与它们的indexOf()

let subjects = ["mathematics", "french", "english", "french", "mathematics"];

let uniqueSubjects = subjects.filter((subject, index) => {
    return subjects.indexOf(subject) === index;
});

console.log(uniqueSubjects); // ["mathematics","french","english"]

假设我们想利用menu 数组,我们首先要循环浏览该数组,将类别存储在一个新的数组中,然后现在利用filter()indexOf() 方法。

let categoriesArray = menu.map((menu)=>menu.category)

let uniqueCategories = categoriesArray.filter((category, index) => {
    return categoriesArray.indexOf(category) === index;
});

console.log(uniqueCategories); // ["breakfast","lunch","dinner"]

如果你想阅读更多关于filter() 方法的信息--请阅读我们的《JavaScript的filter()方法指南》!

使用*reduce()includes()*方法

Reduce总是有点难以掌握,但却能执行一个非常强大的减少操作,这是从函数式编程中借用的。reduce() 方法用于减少数组的元素,并根据你传入的一些减少函数将它们组合成一个最终的数组,而includes() 方法则是在一个元素在数组中时返回真,否则返回假。

下面的例子是对一个数组的元素进行迭代,并检查某个特定的元素是否在结果中,否则我们就把它加上。

let subjects = ["mathematics", "french", "english", "french", "mathematics"];

let uniqueSubjects = subjects.reduce((result, subject) => {
    return result.includes(subject) ? result : [...result, subject];
}, []);

console.log(uniqueSubjects); // ["mathematics","french","english"]

假设我们想利用菜单数组,我们首先要在数组中进行循环,将类别存储在数组中,然后现在利用前面解释的reduce()includes() 方法。

let categoriesArray = menu.map((menu)=>menu.category)

let uniqueCategories = categoriesArray.reduce((result, category) => {
    return result.includes(category) ? result : [...result, category];
}, []);

console.log(uniqueCategories); // ["breakfast","lunch","dinner"]

**注意:**注意我们在这一节中也使用了传播操作符。

使用*forEach()includes()*方法

这与使用filter()includes() 方法的效果差不多。我们只是使用forEach() 方法来遍历数组,然后只向一个新的数组添加尚未存在的元素。

let subjects = ["mathematics", "french", "english", "french", "mathematics"];

let uniqueSubjects = [];
subjects.forEach((subject) => {
    if (!uniqueSubjects.includes(subject)) {
        uniqueSubjects.push(subject);
    }
});

console.log(uniqueSubjects); // ["mathematics","french","english"]

假设我们想利用menu 数组,我们首先要在数组中进行循环,将类别存储在一个数组中,然后再利用前面解释的forEach()includes() 方法。

let categoriesArray = menu.map((menu)=>menu.category)

let uniqueCategories = [];
categoriesArray.forEach((category) => {
    if (!uniqueCategories.includes(category)) {
        uniqueCategories.push(category);
    }
});

console.log(uniqueCategories); // ["breakfast","lunch","dinner"]

结论

在这篇文章中,我们已经看到了四种不同的方法来移除数组中的重复内容。在ES6中引入的Set() ,使之变得更加简单和高效。使用Set() 构造函数从数组中移除重复的元素需要线性时间--O(n) (n 是原数组中元素的数量)。所有其他去除重复的方法都需要O(n²) 。因此,我们强烈建议你在任何可能的情况下使用Set() 构造函数。