从数组中删除重复项

106

我有一个对象数组,看起来像这样:

var array = [
    {id:123, value:"value1", name:"Name1"},
    {id:124, value:"value2", name:"Name1"},
    {id:125, value:"value3", name:"Name2"},
    {id:126, value:"value4", name:"Name2"}
    ...
];

正如您所看到的,一些名称是重复的。我想获得一个仅包含名称的新数组,但如果某个名称重复,我不想再添加它。我想要这个数组:

如上所述,有些名称是重复的。我想获取一个仅含名称的新数组,但如果某个名称重复,则不希望再次添加它。我需要这个数组:

var newArray = ["Name1", "Name2"];

我试图使用 map 来实现这个:

var newArray = array.map((a) => {
    return a.name;
});

但问题在于这会返回:

newArray = ["Name1", "Name1", "Name2", "Name2"];

如何在map中设置某些条件,以便它不会返回已存在的元素? 我想使用map或其他ECMAScript 5或ECMAScript 6功能来实现这一点。


3
从数组中删除重复项。 - Tushar
6
可以考虑使用 Set 吗?https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set - ppasler
1
可能是JavaScript数组中删除重复项的重复问题。 - Bergi
为什么包含id:125的那一行没有以逗号结尾? - Peter Mortensen
请注意,如果数组很大,所有使用.indexOf()的答案都会具有较差的性能,因为它们具有二次时间复杂度。我建议使用ES6 Set或将ES5对象用作字典。 - joeytwiddle
17个回答

1
这就是我使用单独的空数组完成的。

var array = [
   {id:123, value:"value1", name:"Name1"},
   {id:124, value:"value2", name:"Name1"},
   {id:125, value:"value3", name:"Name2"},
   {id:126, value:"value4", name:"Name2"}     
];

var array2 = []  
  
for (i=0; i<array.length;i++){      
   if (array2.indexOf(array[i].name) == -1){    
     array2.push(array[i].name);
    }
}   

console.log(array2) 


0
在ES5中,使用对象作为字典可实现O(n)性能。
但是,此方法仅适用于所有键都是字符串的情况。
var array = [
    {id: 123, value: "value1", name: "Name1"},
    {id: 124, value: "value2", name: "Name1"},
    {id: 125, value: "value3", name: "Name2"},
    {id: 126, value: "value4", name: "Name2"}
];

var allNames = array.map(item => item.name);

var map = {};
allNames.forEach(name => {
  map[name] = true;
});
var uniqueNames = Object.keys(map);

console.log(uniqueNames);

如果你喜欢的话,你可以用一个表达式来完成同样的事情:

var uniqueNames = Object.keys(allNames.reduce((m, n) => (m[n] = true, m), {}));

但我发现命令式形式更易于阅读。


我使用ES6箭头函数来提高代码的清晰度。如果你真的要针对没有转译器的ES5,那么你需要使用完整形式:function (item) { return item.name; } - joeytwiddle
作为 Object.keys() 的替代方案,这个答案 使用 filter() 仅保留那些尚未存储在映射中的名称,这非常优雅。 - joeytwiddle

0

试试这个:

nArr = [];
array.forEach((a) => {
    if (nArr.indexOf(a.name) < 0) { 
        nArr.push(a.name); 
    }
}); 

0

如果你想要最大兼容性和简洁的语法,可以像这样使用array#forEach()array#indexOf()方法:

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }]

// initialize an empty array named names
let names = [];

// iterate through every element of `array` & check if it's 'name' key's value already in names array if not ADD it 
array.forEach(function(element) { if (names.indexOf(element.name) === -1) names.push(element.name) });
// or use tilde like this:
//array.forEach(function(element) { if (~names.indexOf(element.name)) names.push(element.name) });

console.log(names);

然而,如果兼容性不是问题,请使用ECMAScript 6Set对象,array#mapArray.from()方法,如下所示:

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }];

// iterate through every element from array using map and store it in Set(a Set won't have duplicates) then convert the Set back to Array(using Array.from)
let names = Array.from(new Set(array.map(element => element.name)));

console.log(names);


0

我看到有很多类似于spread set的解决方案,但并不是最优的。

这个解决方案更简单、更高效,而且不需要重新创建数组:

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }]

const res = array.map(e => e.name)
                 .filter((e, i, a) => a.indexOf(e) == i)

console.log(res)


-1
var __array=[{id:123, value:"value1", name:"Name1"},{id:124, value:"value2", name:"Name1"},{id:125, value:"value3", name:"Name2"},{id:126, value:"value4", name:"Name2"}];

function __checkArray(__obj){
    var flag = true;
    for(let i=0; i < __array.length; i++){
        if(__obj.id == __array.id){
            flag = false;
            break;
        }
    }

    return flag;
}

var __valToPush = {id: 127, value: "value5", name: "Name3"};
if(__checkArray(__valToPush)){
    __array.push(__valToPush)
}

12
你在使用这么多下划线的时候有特别的原因吗? - Nina Scholz

-1

对于那些寻求一行代码的人

const names = array.reduce((acc, {name}) => acc.includes(name) ? acc : [name, ...acc], []);

或者不使用数组原型上的方法

const { reduce, includes } = Array;
const names = reduce(array, (acc, {name}) => includes(acc, name) ? acc : [name, ...acc], []);

这可能对编写一些处理此类问题的纯函数有用

const get_uniq_values = (key, arr) => reduce(arr, (a, o) => includes(a, o[key]) ? a : [o[key], ...a], []);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接