从 JavaScript 中的对象数组中删除重复项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2218999/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:17:25  来源:igfitidea点击:

Remove duplicates from an array of objects in JavaScript

javascriptarraysobjectduplicates

提问by Travis

I have an object that contains an array of objects.

我有一个包含对象数组的对象。

things = new Object();

things.thing = new Array();

things.thing.push({place:"here",name:"stuff"});
things.thing.push({place:"there",name:"morestuff"});
things.thing.push({place:"there",name:"morestuff"});

I'm wondering what is the best method to remove duplicate objects from an array. So for example, things.thing would become...

我想知道从数组中删除重复对象的最佳方法是什么。例如,things.thing 会变成...

{place:"here",name:"stuff"},
{place:"there",name:"morestuff"}

采纳答案by aefxx

A primitive method would be:

一种原始方法是:

var obj = {};

for ( var i=0, len=things.thing.length; i < len; i++ )
    obj[things.thing[i]['place']] = things.thing[i];

things.thing = new Array();
for ( var key in obj )
    things.thing.push(obj[key]);

回答by Eydrian

How about with some es6magic?

来点es6魔法怎么样?

things.thing = things.thing.filter((thing, index, self) =>
  index === self.findIndex((t) => (
    t.place === thing.place && t.name === thing.name
  ))
)

Reference URL

参考网址

A more generic solution would be:

更通用的解决方案是:

const uniqueArray = things.thing.filter((thing, index) => {
  const _thing = JSON.stringify(thing);
  return index === things.thing.findIndex(obj => {
    return JSON.stringify(obj) === _thing;
  });
});

Stackblitz Example

Stackblitz 示例

回答by ambodi

If you can use Javascript libraries such as underscoreor lodash, I recommend having a look at _.uniqfunction in their libraries. From lodash:

如果您可以使用下划线或 lodash等 Javascript 库,我建议您查看_.uniq它们库中的函数。来自lodash

_.uniq(array, [isSorted=false], [callback=_.identity], [thisArg])

Basically, you pass in the array that in here is an object literal and you pass in the attribute that you want to remove duplicates with in the original data array, like this:

基本上,您传入一个数组,这里是一个对象文字,然后传入要删除原始数据数组中重复项的属性,如下所示:

var data = [{'name': 'Amir', 'surname': 'Rahnama'}, {'name': 'Amir', 'surname': 'Stevens'}];
var non_duplidated_data = _.uniq(data, 'name'); 

UPDATE: Lodash now has introduced a .uniqByas well.

更新:Lodash 现在也引入了.uniqBy

回答by James Drinkard

I had this exact same requirement, to remove duplicate objects in a array, based on duplicates on a single field. I found the code here: Javascript: Remove Duplicates from Array of Objects

我有完全相同的要求,根据单个字段上的重复项删除数组中的重复对象。我在这里找到了代码:Javascript:从对象数组中删除重复项

So in my example, I'm removing any object from the array that has a duplicate licenseNum string value.

因此,在我的示例中,我将从数组中删除具有重复 licenseNum 字符串值的任何对象。

var arrayWithDuplicates = [
    {"type":"LICENSE", "licenseNum": "12345", state:"NV"},
    {"type":"LICENSE", "licenseNum": "A7846", state:"CA"},
    {"type":"LICENSE", "licenseNum": "12345", state:"OR"},
    {"type":"LICENSE", "licenseNum": "10849", state:"CA"},
    {"type":"LICENSE", "licenseNum": "B7037", state:"WA"},
    {"type":"LICENSE", "licenseNum": "12345", state:"NM"}
];

function removeDuplicates(originalArray, prop) {
     var newArray = [];
     var lookupObject  = {};

     for(var i in originalArray) {
        lookupObject[originalArray[i][prop]] = originalArray[i];
     }

     for(i in lookupObject) {
         newArray.push(lookupObject[i]);
     }
      return newArray;
 }

var uniqueArray = removeDuplicates(arrayWithDuplicates, "licenseNum");
console.log("uniqueArray is: " + JSON.stringify(uniqueArray));

The results:

结果:

uniqueArray is:

uniqueArray 是:

[{"type":"LICENSE","licenseNum":"10849","state":"CA"},
{"type":"LICENSE","licenseNum":"12345","state":"NM"},
{"type":"LICENSE","licenseNum":"A7846","state":"CA"},
{"type":"LICENSE","licenseNum":"B7037","state":"WA"}]

回答by chickens

Shortest one liners for ES6+

最短的 ES6+ 内衬

Find unique id's in an array.

id在数组中查找 unique 。

arr.filter((v,i,a)=>a.findIndex(t=>(t.id === v.id))===i)


Unique by multiple properties ( placeand name)

由多个属性(placename)唯一

arr.filter((v,i,a)=>a.findIndex(t=>(t.place === v.place && t.name===v.name))===i)

Unique by all properties (This will be slow for large arrays)

所有属性都是唯一的(这对于大型数组来说会很慢)

arr.filter((v,i,a)=>a.findIndex(t=>(JSON.stringify(t) === JSON.stringify(v)))===i)

Keep the last occurrence.

保留最后一次出现。

arr.slice().reverse().filter((v,i,a)=>a.findIndex(t=>(t.id === v.id))===i).reverse()

回答by Mμ.

One liner using Set

使用 Set 的一个班轮

var things = new Object();

things.thing = new Array();

things.thing.push({place:"here",name:"stuff"});
things.thing.push({place:"there",name:"morestuff"});
things.thing.push({place:"there",name:"morestuff"});

// assign things.thing to myData for brevity
var myData = things.thing;

things.thing = Array.from(new Set(myData.map(JSON.stringify))).map(JSON.parse);

console.log(things.thing)

Explanation:

解释:

  1. new Set(myData.map(JSON.stringify))creates a Setobject using the stringified myData elements.
  2. Set object will ensure that every element is unique.
  3. Then I create an array based on the elements of the created set using Array.from.
  4. Finally, I use JSON.parse to convert stringified element back to an object.
  1. new Set(myData.map(JSON.stringify))使用字符串化的 myData 元素创建一个Set对象。
  2. Set 对象将确保每个元素都是唯一的。
  3. 然后我使用 Array.from 根据创建的集合的元素创建一个数组。
  4. 最后,我使用 JSON.parse 将字符串化元素转换回对象。

回答by V. Sambor

Using ES6+in a single line you can get a unique list of objects by key:

在一行中使用ES6+可以通过键获得唯一的对象列表:

const unique = [...new Map(arr.map(item => [item[key], item])).values()]

It can be put into a function:

它可以放入一个函数中:

function getUniqueListBy(arr, key) {
    return [...new Map(arr.map(item => [item[key], item])).values()]
}

Here is a working example:

这是一个工作示例:

const arr = [
    {place: "here",  name: "x", other: "other stuff1" },
    {place: "there", name: "x", other: "other stuff2" },
    {place: "here",  name: "y", other: "other stuff4" },
    {place: "here",  name: "z", other: "other stuff5" }
]

function getUniqueListBy(arr, key) {
    return [...new Map(arr.map(item => [item[key], item])).values()]
}

const arr1 = getUniqueListBy(arr, 'place')

console.log("Unique by place")
console.log(JSON.stringify(arr1))

console.log("\nUnique by name")
const arr2 = getUniqueListBy(arr, 'name')

console.log(JSON.stringify(arr2))

How does it work

它是如何工作的

First the array is remapped in a way that it can be used as an input for a Map.

首先,数组以一种可以用作Map输入的方式重新映射

arr.map(item => [item[key], item]);

arr.map(item => [item[key], item]);

which means each item of the array will be transformed in another array with 2 elements; the selected keyas first element and the entire initial itemas second element, this is called an entry (ex. array entries, map entries). And here is the official docwith an example showing how to add array entries in Map constructor.

这意味着数组的每一项都将转换为另一个包含 2 个元素的数组;所述选择的键作为第一元件和整个初始项目作为第二元件,这被称为一个条目(例如,阵列的条目映射条目)。而这里是官方的文档与演示如何在地图构造函数到数组项的例子。

Example when key is place:

关键是place 的示例:

[["here", {place: "here",  name: "x", other: "other stuff1" }], ...]

Secondly, we pass this modified array to the Map constructor and here is the magic happening. Map will eliminate the duplicate keys values, keeping only last inserted value of the same key. Note: Map keeps the order of insertion. (check difference between Map and object)

其次,我们将这个修改过的数组传递给 Map 构造函数,这就是神奇的事情发生了。Map 将消除重复的键值,只保留相同键的最后插入值。 注意:Map 保持插入的顺序。(检查地图和对象之间的区别

new Map(entry array just mapped above)

新地图(上面刚刚映射的条目数组)

Third we use the map values to retrieve the original items, but this time without duplicates.

第三,我们使用地图值来检索原始项目,但这次没有重复项。

new Map(mappedArr).values()

新地图(mappedArr).values()

And last one is to add those values into a fresh new array so that it can look as the initial structure and return that:

最后一个是将这些值添加到一个新的数组中,这样它就可以作为初始结构并返回:

return [...new Map(mappedArr).values()]

返回 [...new Map(mappedArr).values()]

回答by Alex Kobylinski

Here's another option to do it using Array iterating methods if you need comparison only by one field of an object:

如果您只需要通过对象的一个​​字段进行比较,这是使用数组迭代方法的另一种选择:

    function uniq(a, param){
        return a.filter(function(item, pos, array){
            return array.map(function(mapItem){ return mapItem[param]; }).indexOf(item[param]) === pos;
        })
    }

    uniq(things.thing, 'place');

回答by sravan ganji

one liner is here

一艘班轮在这里

let arr = [
  {id:1,name:"sravan ganji"},
  {id:2,name:"anu"},
  {id:4,name:"mammu"},
  {id:3,name:"sanju"},
  {id:3,name:"ram"},
];

console.log(Object.values(arr.reduce((acc,cur)=>Object.assign(acc,{[cur.id]:cur}),{})))

回答by аlex dyky?

The simplest way is use filter:

最简单的方法是使用filter

var uniq = {}
var arr  = [{"id":"1"},{"id":"1"},{"id":"2"}]
var arrFiltered = arr.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true));
console.log('arrFiltered', arrFiltered)