如何从对象数组中删除所有重复项?

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

obj = {};
obj.arr = new Array();
obj.arr.push({place:"here",name:"stuff"});obj.arr.push({place:"there",name:"morestuff"});obj.arr.push({place:"there",name:"morestuff"});

我想知道从数组中删除重复对象的最佳方法是什么。例如,obj.arr将成为…

{place:"here",name:"stuff"},{place:"there",name:"morestuff"}
1025775 次浏览

一个原始的方法是:

const obj = {};
for (let i = 0, len = things.thing.length; i < len; i++) {obj[things.thing[i]['place']] = things.thing[i];}
things.thing = new Array();
for (const key in obj) {things.thing.push(obj[key]);}

这是一种通用的方法:传入一个函数,该函数测试数组的两个元素是否被视为相等。在这种情况下,它比较被比较的两个对象的nameplace属性的值。

es5答案

function removeDuplicates(arr, equals) {var originalArr = arr.slice(0);var i, len, val;arr.length = 0;
for (i = 0, len = originalArr.length; i < len; ++i) {val = originalArr[i];if (!arr.some(function(item) { return equals(item, val); })) {arr.push(val);}}}
function thingsEqual(thing1, thing2) {return thing1.place === thing2.place&& thing1.name === thing2.name;}
var things = [{place:"here",name:"stuff"},{place:"there",name:"morestuff"},{place:"there",name:"morestuff"}];
removeDuplicates(things, thingsEqual);console.log(things);

原ES3答案

function arrayContains(arr, val, equals) {var i = arr.length;while (i--) {if ( equals(arr[i], val) ) {return true;}}return false;}
function removeDuplicates(arr, equals) {var originalArr = arr.slice(0);var i, len, j, val;arr.length = 0;
for (i = 0, len = originalArr.length; i < len; ++i) {val = originalArr[i];if (!arrayContains(arr, val, equals)) {arr.push(val);}}}
function thingsEqual(thing1, thing2) {return thing1.place === thing2.place&& thing1.name === thing2.name;}
removeDuplicates(things.thing, thingsEqual);

如果你可以等到所有添加之后再消除重复项,典型的方法是首先对数组进行排序,然后消除重复项。排序避免了在遍历每个元素时扫描数组的N*N方法。

“消除重复”功能通常称为独特uniq。一些现有的实现可以结合这两个步骤,例如原型的uniq

这篇文章没有什么想法可以尝试(有些是为了避免 :-) ) 如果你的图书馆还没有!就我个人而言,我发现这是最直接的:

    function unique(a){a.sort();for(var i = 1; i < a.length; ){if(a[i-1] == a[i]){a.splice(i, 1);} else {i++;}}return a;}
// Provide your own comparisonfunction unique(a, compareFunc){a.sort( compareFunc );for(var i = 1; i < a.length; ){if( compareFunc(a[i-1], a[i]) === 0){a.splice(i, 1);} else {i++;}}return a;}

如果您可以使用Javascript库,例如强调或洛达什,我建议您在他们的库中查看_.uniq函数。从lodash开始:

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

基本上,您传入此处为对象文字的数组,并传入要在原始数据数组中删除重复项的属性,如下所示:

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

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

另一种选择是创建一个自定义indexOf函数,该函数比较每个对象的所选属性的值并将其包装在Reduce函数中。

var uniq = redundant_array.reduce(function(a,b){function indexOfProperty (a, b){for (var i=0;i<a.length;i++){if(a[i].property == b.property){return i;}}return -1;}
if (indexOfProperty(a,b) < 0 ) a.push(b);return a;},[]);

这是另一种技术来找到重复的数量,并轻松地从您的数据对象中删除它。“dupsCount”是重复文件数。首先排序您的数据,然后删除。它将为您提供最快的重复删除。

  dataArray.sort(function (a, b) {var textA = a.name.toUpperCase();var textB = b.name.toUpperCase();return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;});for (var i = 0; i < dataArray.length - 1; ) {if (dataArray[i].name == dataArray[i + 1].name) {dupsCount++;dataArray.splice(i, 1);} else {i++;}}

如果您只需要通过对象的一个字段进行比较,则可以使用Array迭代方法进行比较:

    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');

es6魔法怎么样?

obj.arr = obj.arr.filter((value, index, self) =>index === self.findIndex((t) => (t.place === value.place && t.name === value.name)))

引用URL

更通用的解决方案是:

const uniqueArray = obj.arr.filter((value, index) => {const _value = JSON.stringify(value);return index === obj.arr.findIndex(obj => {return JSON.stringify(obj) === _value;});});

使用上面的属性策略而不是JSON.stringify

const isPropValuesEqual = (subject, target, propNames) =>propNames.every(propName => subject[propName] === target[propName]);
const getUniqueItemsByProperties = (items, propNames) =>items.filter((item, index, array) =>index === array.findIndex(foundItem => isPropValuesEqual(foundItem, item, propNames)));

如果您希望propNames属性是数组或值,您可以添加包装器:

const getUniqueItemsByProperties = (items, propNames) => {const propNamesArray = Array.from(propNames);
return items.filter((item, index, array) =>index === array.findIndex(foundItem => isPropValuesEqual(foundItem, item, propNamesArray)));};

允许getUniqueItemsByProperties('a')getUniqueItemsByProperties(['a']);

Stackblitz示例

补充说明

  • 首先了解使用的两种方法:
  • 接下来,把你的想法使你的两个对象相等,并记住这一点。
  • 我们可以检测到重复的东西,如果它满足我们刚刚想到的标准,但它的位置不是在具有该标准的对象的第一个实例。
  • 因此,我们可以使用上述标准来确定某物是否是重复的。

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

因此,在我的示例中,我从数组中删除了具有重复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));

结果:

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"}]

这是一个使用JavaScript新过滤器函数的解决方案,非常简单。假设您有一个这样的数组。

var duplicatesArray = ['AKASH','AKASH','NAVIN','HARISH','NAVIN','HARISH','AKASH','MANJULIKA','AKASH','TAPASWENI','MANJULIKA','HARISH','TAPASWENI','AKASH','MANISH','HARISH','TAPASWENI','MANJULIKA','MANISH'];

filter函数将允许您创建一个新数组,对数组中的每个元素使用一次回调函数。因此,您可以像这样设置唯一的数组。

var uniqueArray = duplicatesArray.filter(function(elem, pos) {return duplicatesArray.indexOf(elem) == pos;});

在这种情况下,你的唯一数组将运行重复数组中的所有值。elem变量表示数组中元素的值(mike, james, james, alex),位置是它在数组中的0索引位置(0,1,2,3…),duplicatesArray.indexOf(elem)值只是该元素在原始数组中第一次出现的索引。所以,因为元素'james'是重复的,当我们遍历重复数组中的所有元素并将它们推送到uniqueArray时,我们第一次命中james时,我们的“pos”值是1,我们的indexOf(elem)也是1,所以James被推送到uniqueArray。第二次命中James时,我们的“pos”值为2,而我们的indexOf(elem)仍然为1(因为它只找到数组元素的第一个实例),因此不会推送重复。因此,我们的uniqueArray只包含唯一值。

这是上面函数的Demo。单击此处查看上面的函数示例

如果您需要一个基于对象中多个属性的唯一数组,您可以使用map并组合对象的属性来执行此操作。

    var hash = array.map(function(element){var string = ''for (var key in element){string += element[key]}return string})array = array.filter(function(element, index){var string = ''for (var key in element){string += element[key]}return hash.indexOf(string) == index})

您也可以使用Map

const dedupThings = Array.from(things.thing.reduce((m, t) => m.set(t.place, t), new Map()).values());

完整样本:

const 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"});
const dedupThings = Array.from(things.thing.reduce((m, t) => m.set(t.place, t), new Map()).values());
console.log(JSON.stringify(dedupThings, null, 4));

结果:

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

任何对象数组的泛型:

/*** Remove duplicated values without losing information*/const removeValues = (items, key) => {let tmp = {};
items.forEach(item => {tmp[item[key]] = (!tmp[item[key]]) ? item : Object.assign(tmp[item[key]], item);});items = [];Object.keys(tmp).forEach(key => items.push(tmp[key]));
return items;}

希望它可以帮助任何人。

一个衬垫使用设置

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 brevityvar myData = things.thing;
things.thing = Array.from(new Set(myData.map(JSON.stringify))).map(JSON.parse);
console.log(things.thing)

说明:

  1. new Set(myData.map(JSON.stringify))使用字符串化的myData元素创建设置对象。
  2. Set对象将确保每个元素都是唯一的。
  3. 然后我基于创建的集合的元素创建一个数组,使用Array.from.
  4. 最后,我使用JSON.parse将字符串化元素转换回对象。
let data = [{'name': 'Amir','surname': 'Rahnama'},{'name': 'Amir','surname': 'Stevens'}];let non_duplicated_data = _.uniqBy(data, 'name');

另一种方法是使用duce函数并有一个新数组作为累加器。如果累加器数组中已经有一个同名的thing,则不要将其添加到那里。

let list = things.thing;list = list.reduce((accumulator, thing) => {if (!accumulator.filter((duplicate) => thing.name === duplicate.name)[0]) {accumulator.push(thing);}return accumulator;}, []);thing.things = list;

我添加了这个答案,因为我找不到与Internet Explorer 11兼容的好的、可读的es6解决方案(我使用Babel来处理箭头函数)。问题是IE11没有Map.values()Set.values()而不使用poly填充。出于同样的原因,我使用filter()[0]来获取第一个元素而不是find()

考虑到lodash.uniqWith

const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; 
_.uniqWith(objects, _.isEqual);// => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
 var testArray= ['a','b','c','d','e','b','c','d'];
function removeDuplicatesFromArray(arr){
var obj={};var uniqueArr=[];for(var i=0;i<arr.length;i++){if(!obj.hasOwnProperty(arr[i])){obj[arr[i]] = arr[i];uniqueArr.push(arr[i]);}}
return uniqueArr;
}var newArr = removeDuplicatesFromArray(testArray);console.log(newArr);
Output:- [ 'a', 'b', 'c', 'd', 'e' ]

如果你不介意之后对你的唯一数组进行排序,这将是一个有效的解决方案:

things.thing.sort(((a, b) => a.place < b.place).filter((current, index, array) =>index === 0 || current.place !== array[index - 1].place)

这样,你只需将当前元素与数组中的前一个元素进行比较。在过滤(O(n*log(n)))之前排序一次比在整个数组中为每个数组元素(O(n²))搜索重复项便宜。

这是如何从对象数组中删除二重性的简单方法。

我经常使用数据,这对我很有用。

const data = [{name: 'AAA'}, {name: 'AAA'}, {name: 'BBB'}, {name: 'AAA'}];function removeDuplicity(datas){return datas.filter((item, index,arr)=>{const c = arr.map(item=> item.name);return  index === c.indexOf(item.name)})}
console.log(removeDuplicity(data))

将打印到控制台:

[[object Object] {name: "AAA"}, [object Object] {name: "BBB"}]

在列表中再添加一个。使用ES6和Array.reduceArray.find
在此示例中,根据guid属性过滤对象。

let filtered = array.reduce((accumulator, current) => {if (! accumulator.find(({guid}) => guid === current.guid)) {accumulator.push(current);}return accumulator;}, []);

扩展此选项以允许选择属性并将其压缩为一个衬里:

const uniqify = (array, key) => array.reduce((prev, curr) => prev.find(a => a[key] === curr[key]) ? prev : prev.push(curr) && prev, []);

要使用它,请传递一个对象数组和您希望将其作为字符串值进行去重复处理的键的名称:

const result = uniqify(myArrayOfObjects, 'guid')
str =[{"item_id":1},{"item_id":2},{"item_id":2}]
obj =[]for (x in str){if(check(str[x].item_id)){obj.push(str[x])}}function check(id){flag=0for (y in obj){if(obj[y].item_id === id){flag =1}}if(flag ==0) return trueelse return false
}console.log(obj)

str是一个对象数组。存在具有相同值的对象(这里是一个小例子,有两个对象具有与2相同的item_id)。校验是一个检查是否存在具有相同item_id的对象的函数。如果存在,则返回false,否则返回true。根据该结果,将对象推送到一个新的数组obj上面代码的输出是[{"item_id":1},{"item_id":2}]

该死,孩子们,让我们把这东西压垮,为什么不呢?

let uniqIds = {}, source = [{id:'a'},{id:'b'},{id:'c'},{id:'b'},{id:'a'},{id:'d'}];let filtered = source.filter(obj => !uniqIds[obj.id] && (uniqIds[obj.id] = true));console.log(filtered);// EXPECTED: [{id:'a'},{id:'b'},{id:'c'},{id:'d'}];

ES6一号线在这里

let arr = [{id:1,name:"sravan ganji"},{id:2,name:"pinky"},{id:4,name:"mammu"},{id:3,name:"avy"},{id:3,name:"rashni"},];
console.log(Object.values(arr.reduce((acc,cur)=>Object.assign(acc,{[cur.id]:cur}),{})))

你听说过Lodash图书馆吗?当您不想将逻辑应用于代码时,我向您推荐此实用程序,并使用已优化且可靠的现有代码。

考虑制作这样的数组

things.thing.push({place:"utopia",name:"unicorn"});things.thing.push({place:"jade_palace",name:"po"});things.thing.push({place:"jade_palace",name:"tigress"});things.thing.push({place:"utopia",name:"flying_reindeer"});things.thing.push({place:"panda_village",name:"po"});

请注意,如果您想保持一个属性的唯一性,您可以通过使用洛达什库来做到这一点。在这里,您可以使用_. uniqBy

. uniqBy(数组,[迭代器=.identity])

此方法类似于_. uniq(它返回数组的无重复版本,其中仅保留每个元素的第一个匹配项),除了它接受迭代,该迭代为数组中的每个元素调用以生成计算唯一性的标准。

因此,例如,如果您想返回具有唯一属性“place”的数组

_. uniqBy(things.thing,'place')

同样,如果你想要唯一的属性作为'name'

_. uniqBy(things.thing,'name')

希望这有帮助。

干杯!

如果不想指定属性列表:

function removeDuplicates(myArr) {var props = Object.keys(myArr[0])return myArr.filter((item, index, self) =>index === self.findIndex((t) => (props.every(prop => {return t[prop] === item[prop]}))))}

OBS!与IE11不兼容。

function filterDuplicateQueries(queries){let uniqueQueries = [];queries.forEach((l, i)=>{let alreadyExist = false;if(uniqueQueries.length>0){uniqueQueries.forEach((k, j)=>{if(k.query == l.query){alreadyExist = true;}});}if(!alreadyExist){uniqueQueries.push(l)}});

这是ES6的解决方案,您只想保留最后一项。此解决方案功能齐全,符合Airbnb风格。

const things = {thing: [{ place: 'here', name: 'stuff' },{ place: 'there', name: 'morestuff1' },{ place: 'there', name: 'morestuff2' },],};
const removeDuplicates = (array, key) => {return array.reduce((arr, item) => {const removed = arr.filter(i => i[key] !== item[key]);return [...removed, item];}, []);};
console.log(removeDuplicates(things.thing, 'place'));// > [{ place: 'here', name: 'stuff' }, { place: 'there', name: 'morestuff2' }]

removeDuplicates()接收一个对象数组并返回一个没有任何重复对象的新数组(基于id属性)。

const allTests = [{name: 'Test1', id: '1'},{name: 'Test3', id: '3'},{name: 'Test2', id: '2'},{name: 'Test2', id: '2'},{name: 'Test3', id: '3'}];
function removeDuplicates(array) {let uniq = {};return array.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true))}
removeDuplicates(allTests);

预期成果:

[{name: 'Test1', id: '1'},{name: 'Test3', id: '3'},{name: 'Test2', id: '2'}];

首先,我们将变量uniq的值设置为一个空对象。

接下来,我们过滤对象数组。Filter创建一个新数组,其中包含通过所提供函数实现的测试的所有元素。

return array.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true));

上面,我们使用&&的短路功能。如果&&的左侧评估为真,则返回&&右侧的值。如果左侧为假,则返回&&左侧的值。

对于每个对象(obj),我们检查uniq中名为obj.id的属性(在这种情况下,在第一次迭代中,它将检查属性'1')。我们想要它返回的内容相反(无论是true还是false),这就是我们在!uniq[obj.id]中使用!的原因。如果uniq已经有了id属性,它返回true,其计算结果为false(!),告诉过滤器函数不要添加该obj。然而,如果它没有找到obj.id属性,它返回false,然后计算结果为true(!)并将所有内容返回到&&的右侧,或(uniq[obj.id]=true)。这是一个truthy值,告诉filter方法将该obj添加到返回的数组中,它还将属性{1: true}添加到uniq。这确保不会再次添加具有相同id的任何其他obj实例。

  • 此解决方案对于任何类型的对象都是通用的,并检查数组中Object中的每个(key, value)
  • 使用临时对象作为哈希表来查看整个Object是否曾经作为键存在。
  • 如果找到Object的字符串表示,则从数组中删除该项目。

var arrOfDup = [{'id':123, 'name':'name', 'desc':'some desc'},{'id':125, 'name':'another name', 'desc':'another desc'},{'id':123, 'name':'name', 'desc':'some desc'},{'id':125, 'name':'another name', 'desc':'another desc'},{'id':125, 'name':'another name', 'desc':'another desc'}];
function removeDupes(dupeArray){let temp = {};let tempArray = JSON.parse(JSON.stringify(dupeArray));dupeArray.forEach((item, pos) => {if(temp[JSON.stringify(item)]){tempArray.pop();}else{temp[JSON.stringify(item)] = item;}});return tempArray;}
arrOfDup = removeDupes(arrOfDup);
arrOfDup.forEach((item, pos) => {console.log(`item in array at position ${pos} is ${JSON.stringify(item)}`);});

继续探索从对象数组中删除重复项的ES6方法:将Array.prototype.filterthisArg参数设置为new Set提供了一个不错的选择:

const things = [{place:"here",name:"stuff"},{place:"there",name:"morestuff"},{place:"there",name:"morestuff"}];
const filtered = things.filter(function({place, name}) {
const key =`${place}${name}`;
return !this.has(key) && this.add(key);
}, new Set);
console.log(filtered);

但是,它不适用于箭头函数() =>,因为this绑定到它们的词法范围。

要从对象数组中删除所有重复项,最简单的方法是使用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);

es6魔法在一行…可读的!

// returns the union of two arrays where duplicate objects with the same 'prop' are removedconst removeDuplicatesWith = (a, b, prop) => {a.filter(x => !b.find(y => x[prop] === y[prop]));};

这是我的解决方案,它根据object.prop搜索重复项,当它找到一个重复对象时,它在array1with array2 valuereplaces its value

function mergeSecondArrayIntoFirstArrayByProperty(array1, array2) {for (var i = 0; i < array2.length; i++) {var found = false;for (var j = 0; j < array1.length; j++) {if (array2[i].prop === array1[j].prop) { // if item exist in array1array1[j] = array2[i]; // replace it in array1 with array2 valuefound = true;}}if (!found) // if item in array2 not found in array1, add it to array1array1.push(array2[i]);
}return array1;}

这个怎么样:

function dedupe(arr, compFn){let res = [];if (!compFn) compFn = (a, b) => { return a === b };arr.map(a => {if(!res.find(b => compFn(a, b))) res.push(a)});return res;}

如果您发现自己需要经常从基于特定字段的数组中删除重复对象,那么可能值得创建一个distinct(array, predicate)函数,您可以从项目中的任何位置导入该函数。这看起来像

const things = [{place:"here",name:"stuff"}, ...];const distinctThings = distinct(things, thing => thing.place);

不同的函数可以使用上面许多好答案中给出的任何实现。最简单的使用findIndex

const distinct = (items, predicate) => items.filter((uniqueItem, index) =>items.findIndex(item =>predicate(item) === predicate(uniqueItem)) === index);

来源

JSFiddle

这将删除重复对象而不传递任何键。

uniqueArray = a => [...new Set(a.map(o => JSON.stringify(o)))].map(s => JSON.parse(s));
var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
var unique = uniqueArray(objects);console.log('Original Object',objects);console.log('Unique',unique);

uniqueArray = a => [...new Set(a.map(o => JSON.stringify(o)))].map(s => JSON.parse(s));
var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
var unique = uniqueArray(objects);console.log(objects);console.log(unique);
const uniqueElements = (arr, fn) => arr.reduce((acc, v) => {if (!acc.some(x => fn(v, x))) { acc.push(v); }return acc;}, []);
const stuff = [{place:"here",name:"stuff"},{place:"there",name:"morestuff"},{place:"there",name:"morestuff"},];
const unique = uniqueElements(stuff, (a,b) => a.place === b.place && a.name === b.name );
//console.log( unique );
[{"place": "here","name": "stuff"},{"place": "there","name": "morestuff"}]

您可以将Object.values()Array.prototype.reduce()组合使用:

const 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"});
const result = Object.values(things.thing.reduce((a, c) => (a[`${c.place}${c.name}`] = c, a), {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

let myData = [{place:"here",name:"stuff"},{place:"there",name:"morestuff"},{place:"there",name:"morestuff"}];

let q = [...new Map(myData.map(obj => [JSON.stringify(obj), obj])).values()];
console.log(q)

单行使用ES6和new Map()

// assign things.thing to myDatalet myData = things.thing;
[...new Map(myData.map(obj => [JSON.stringify(obj), obj])).values()];

详情:-

  1. 在数据列表上执行.map()并将每个单独的对象转换为[key, value]对数组(长度=2),第一个元素(键)将是对象的stringified版本,第二个(值)将是object本身。
  2. 将上面创建的数组列表添加到new Map()将使键作为stringified对象,任何相同的键添加都将导致覆盖已经存在的键。
  3. 使用.values()将为MapIterator提供Map中的所有值(在我们的例子中为obj
  4. 最后,spread ...运算符用上述步骤中的值给出新数组。

让事情变得简单。花哨是好的,但不可读的代码是无用的。享受:-)

var a = [{executiveId: 6873702,largePhotoCircle: null,name: "John A. Cuomo",photoURL: null,primaryCompany: "VSE CORP",primaryTitle: "Chief Executive Officer, President and Director"},{executiveId: 6873702,largePhotoCircle: null,name: "John A. Cuomo",photoURL: null,primaryCompany: "VSE CORP",primaryTitle: "Chief Executive Officer, President and Director"},{executiveId: 6873703,largePhotoCircle: null,name: "John A. Cuomo",photoURL: null,primaryCompany: "VSE CORP",primaryTitle: "Chief Executive Officer, President and Director",}];
function filterDuplicate(myArr, prop) {// Format - (1)
// return myArr.filter((obj, pos, arr) => {//     return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;// });
// Format - (2)var res = {};var resArr = [];for (var elem of myArr) {res[elem.executiveId] = elem;}for (let [index, elem] of Object.entries(res)) {resArr.push(elem);}return resArr;}  
let finalRes = filterDuplicate(a,"executiveId");console.log("finalResults : ",finalRes);

您可以将数组对象转换为字符串,以便对它们进行比较,将字符串添加到Set中,以便自动删除可比较的重复项,然后将每个字符串转换回对象。

它可能不像其他答案那样高性能,但它是可读的。

const things = {};
things.thing = [];things.thing.push({place:"here",name:"stuff"});things.thing.push({place:"there",name:"morestuff"});things.thing.push({place:"there",name:"morestuff"});
const uniqueArray = (arr) => {
const stringifiedArray = arr.map((item) => JSON.stringify(item));const set = new Set(stringifiedArray);
return Array.from(set).map((item) => JSON.parse(item));}
const uniqueThings = uniqueArray(things.thing);
console.log(uniqueThings);

TypeScript解决方案

这将删除重复的对象并保留对象的类型。

function removeDuplicateObjects(array: any[]) {return [...new Set(array.map(s => JSON.stringify(s)))].map(s => JSON.parse(s));}

使用ES6“减少”和“查找”数组助手方法的简单解决方案

工作效率和完美的罚款!

"use strict";
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"});
// the logic is here
function removeDup(something) {return something.thing.reduce(function (prev, ele) {var found = prev.find(function (fele) {return ele.place === fele.place && ele.name === fele.name;});if (!found) {prev.push(ele);}return prev;}, []);}console.log(removeDup(things));

一个带过滤器的衬垫(保留订单)

在数组中查找唯一的id

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

如果顺序不重要,地图解决方案会更快:地图解决方案


由多个属性(placename)唯一

arr.filter((v,i,a)=>a.findIndex(v2=>['place','name'].every(k=>v2[k] ===v[k]))===i)

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

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

保留最后一次出现findLastIndex替换findIndex

arr.filter((v,i,a)=>a.findLastIndex(v2=>(v2.place === v.place))===i)

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

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

它可以放在一个函数中:

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

下面是一个工作示例:

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))

它是如何工作的

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

arr.map(项目=>[项目[键],项目]);

这意味着数组的每个项都将在另一个包含2个元素的数组中转换;选定的关键作为第一个元素,整个初始项目作为第二个元素,这称为条目(例如数组条目地图条目)。这是官方文档带有一个示例,展示了如何在Map构造函数中添加数组条目。

例如key为地方

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

其次,我们将这个修改后的数组传递给Map构造函数,神奇的事情发生了。Map将消除重复的键值,仅保留同一键的最后插入值。注意:Map保持插入顺序。(检查Map和Object之间的差异

new Map(上面刚刚映射的条目数组)

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

new Map(mapapedArr)//新映射

最后一个是将这些值添加到一个新的新数组中,以便它可以看起来像初始结构并返回:

返回[… new Map(mapepdArr). value()]

如果您严格地想要删除基于一个属性的重复项,您可以将数组reduce转换为基于place属性的对象,因为对象只能有唯一的键,然后您可以只获取values以返回数组:

const unique = Object.values(things.thing.reduce((o, t) => ({ ...o, [t.place]: t }), {}))

您还可以创建一个泛型函数,该函数将根据您传递给函数的对象键过滤数组

function getUnique(arr, comp) {
return arr.map(e => e[comp]).map((e, i, final) => final.indexOf(e) === i && i)  // store the keys of the unique objects.filter(e => arr[e]).map(e => arr[e]); // eliminate the dead keys & store unique objects
}

你可以像这样调用函数,

getUnique(things.thing,'name') // to filter on basis of name
getUnique(things.thing,'place') // to filter on basis of place

对于一个可读和简单的解决方案搜索者,她是我的版本:

    function removeDupplicationsFromArrayByProp(originalArray, prop) {let results = {};for(let i=0; i<originalArray.length;i++){results[originalArray[i][prop]] = originalArray[i];}return Object.values(results);}

这种方式对我很有效:

function arrayUnique(arr, uniqueKey) {const flagList = new Set()return arr.filter(function(item) {if (!flagList.has(item[uniqueKey])) {flagList.add(item[uniqueKey])return true}})}const data = [{name: 'Kyle',occupation: 'Fashion Designer'},{name: 'Kyle',occupation: 'Fashion Designer'},{name: 'Emily',occupation: 'Web Designer'},{name: 'Melissa',occupation: 'Fashion Designer'},{name: 'Tom',occupation: 'Web Developer'},{name: 'Tom',occupation: 'Web Developer'}]console.table(arrayUnique(data, 'name'))// work well

打印输出

┌─────────┬───────────┬────────────────────┐│ (index) │   name    │     occupation     │├─────────┼───────────┼────────────────────┤│    0    │  'Kyle'   │ 'Fashion Designer' ││    1    │  'Emily'  │   'Web Designer'   ││    2    │ 'Melissa' │ 'Fashion Designer' ││    3    │   'Tom'   │  'Web Developer'   │└─────────┴───────────┴────────────────────┘

ES5:

function arrayUnique(arr, uniqueKey) {const flagList = []return arr.filter(function(item) {if (flagList.indexOf(item[uniqueKey]) === -1) {flagList.push(item[uniqueKey])return true}})}

这两种方式更简单,更容易理解。

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"});console.log(things);function removeDuplicate(result, id) {let duplicate = {};return result.filter(ele => !duplicate[ele[id]] &&                   (duplicate[ele[id]] = true));}let resolverarray = removeDuplicate(things.thing,'place')console.log(resolverarray);

我相信reduceJSON.stringify完美比较对象和选择性地的组合添加那些尚未在累加器中的对象是一种优雅的方式。

请记住,在数组具有许多对象并且它们很复杂的极端情况下,JSON.stringify可能会成为性能问题,但对于大部分时间,这是去IMHO的最短方式。

var collection= [{a:1},{a:2},{a:1},{a:3}]
var filtered = collection.reduce((filtered, item) => {if( !filtered.some(filteredItem => JSON.stringify(filteredItem) == JSON.stringify(item)) )filtered.push(item)return filtered}, [])
console.log(filtered)

另一种写作方式相同(但效率较低):

collection.reduce((filtered, item) =>filtered.some(filteredItem =>JSON.stringify(filteredItem ) == JSON.stringify(item))? filtered: [...filtered, item], [])

如果您想基于所有参数而不仅仅是一个参数来消除数组的重复。您可以使用可以将函数作为第二个参数的洛塔什的uniqBy函数。

您将拥有此单行代码:

 _.uniqBy(array, e => { return e.place && e.name })

我的两分钱在这里。如果您知道属性的顺序相同,您可以stringify元素并从数组中删除欺骗并再次解析数组。像这样的东西:

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"});  
let stringified = things.thing.map(i=>JSON.stringify(i));let unique =  stringified.filter((k, idx)=> stringified.indexOf(k) === idx).map(j=> JSON.parse(j))console.log(unique);

function dupData() {var arr = [{ comment: ["a", "a", "bbb", "xyz", "bbb"] }];let newData = [];comment.forEach(function (val, index) {if (comment.indexOf(val, index + 1) > -1) {if (newData.indexOf(val) === -1) { newData.push(val) }}})}
 npm i lodash
let non_duplicated_data = _.uniqBy(pendingDeposits, v => [v.stellarAccount, v.externalTransactionId].join());
    function genFilterData(arr, key, key1) {let data = [];data = [...new Map(arr.map((x) => [x[key] || x[key1], x])).values()];    
const makeData = [];for (let i = 0; i < data.length; i += 1) {makeData.push({ [key]: data[i][key], [key1]: data[i][key1] });}    
return makeData;}const arr = [{make: "here1", makeText:'hj',k:9,l:99},{make: "here", makeText:'hj',k:9,l:9},{make: "here", makeText:'hj',k:9,l:9}]
const finalData= genFilterData(data, 'Make', 'MakeText');    
console.log(finalData);

我知道这个问题已经有很多答案了,但是请耐心听我说…

数组中的某些对象可能具有您不感兴趣的其他属性,或者您只是想找到唯一对象只考虑属性的子集

考虑下面的数组。假设您只想在此数组中找到仅考虑propOnepropTwo的唯一对象,并忽略可能存在的任何其他属性。

预期的结果应该只包括第一个和最后一个对象。所以代码如下:

const array = [{propOne: 'a',propTwo: 'b',propThree: 'I have no part in this...'},{propOne: 'a',propTwo: 'b',someOtherProperty: 'no one cares about this...'},{propOne: 'x',propTwo: 'y',yetAnotherJunk: 'I am valueless really',noOneHasThis: 'I have something no one has'}];
const uniques = [...new Set(array.map(x => JSON.stringify(((o) => ({propOne: o.propOne,propTwo: o.propTwo}))(x))))].map(JSON.parse);
console.log(uniques);

 const things = [{place:"here",name:"stuff"},{place:"there",name:"morestuff"},{place:"there",name:"morestuff"}];const filteredArr = things.reduce((thing, current) => {const x = thing.find(item => item.place === current.place);if (!x) {return thing.concat([current]);} else {return thing;}}, []);console.log(filteredArr)

通过Set对象解决方案|根据数据类型

const seen = new Set();const things = [{place:"here",name:"stuff"},{place:"there",name:"morestuff"},{place:"there",name:"morestuff"}];
const filteredArr = things.filter(el => {const duplicate = seen.has(el.place);seen.add(el.place);return !duplicate;});console.log(filteredArr)

Set对象特征

Set Object中的每个值必须是唯一的,值相等将被检查

根据数据类型存储唯一值的设置对象的目的,无论是原始值还是对象references.it有四个非常有用的实例方法addclearhasdelete

独特的数据类型功能:…

add方法

默认情况下,它将唯一数据推送到集合中,同时保留数据类型…这意味着它防止将重复项推送到集合中,默认情况下它将检查数据类型…

has方法

有时需要检查数据项是否存在于集合中,并且。这是集合识别唯一ID或项目和数据类型的方便方法。

delete方法

它将通过标识数据类型从集合中删除特定项。

clear方法

它将从一个特定变量中删除所有集合项并设置为空对象

Set对象也有迭代方法和更多功能…

最好从这里阅读:设置-JavaScript|MDN

具有更好运行时间的简单高性能解决方案比已经存在的70多个答案:

const ids = array.map(o => o.id)const filtered = array.filter(({id}, index) => !ids.includes(id, index + 1))

示例:

const arr = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 1, name: 'one'}]
const ids = arr.map(o => o.id)const filtered = arr.filter(({id}, index) => !ids.includes(id, index + 1))
console.log(filtered)

它是如何工作的:

Array.filter()通过检查先前映射的id数组是否包含当前id({id}将对象分解为其id)来删除所有重复对象。为了只过滤掉实际的重复项,它使用Array.includes()的第二个参数fromIndexindex + 1,这将忽略当前对象和所有以前的对象。

由于filter回调方法的每次迭代只会搜索从当前索引+1开始的数组,这也大大减少了运行时,因为只有先前未过滤的对象才会被检查。

这显然也适用于任何其他不称为id、多个甚至所有键的键。

这个问题可以简化为从thing数组中删除重复项。

您可以通过使用对象来维护唯一标准作为键并存储关联值来实现更快的O(n)解决方案(假设本机键查找可以忽略不计)。

基本上,这个想法是通过它们唯一的键存储所有对象,以便重复项覆盖它们自己:

const thing = [{ place: "here", name:"stuff" }, { place: "there", name:"morestuff" }, { place: "there", name:"morestuff" } ]
const uniques = {}for (const t of thing) {const key = t.place + '$' + t.name  // Or whatever string criteria you want, which can be generified as Object.keys(t).join("$")uniques[key] = t                    // Last duplicate wins}const uniqueThing = Object.values(uniques)console.log(uniqueThing)

如果您使用的是Lodash库,您也可以使用以下函数。它应该删除重复的对象。

var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];_.uniqWith(objects, _.isEqual);

我认为最好的方法是使用减少地图对象这是一个单线解决方案。

const data = [{id: 1, name: 'David'},{id: 2, name: 'Mark'},{id: 2, name: 'Lora'},{id: 4, name: 'Tyler'},{id: 4, name: 'Donald'},{id: 5, name: 'Adrian'},{id: 6, name: 'Michael'}]
const uniqueData = [...data.reduce((map, obj) => map.set(obj.id, obj), new Map()).values()];
console.log(uniqueData)
/*in `map.set(obj.id, obj)`  
'obj.id' is key. (don't worry. we'll get only values using the .values() method)'obj' is whole object.*/

const objectsMap = new Map();const placesName = [{ place: "here", name: "stuff" },{ place: "there", name: "morestuff" },{ place: "there", name: "morestuff" },];placesName.forEach((object) => {objectsMap.set(object.place, object);});console.log(objectsMap);

这个解决方案最适合我,利用Array.from方法,而且它更短,更可读。

let person = [{name: "john"},{name: "jane"},{name: "imelda"},{name: "john"},{name: "jane"}];
const data = Array.from(new Set(person.map(JSON.stringify))).map(JSON.parse);console.log(data);
  • 在React js中从对象数组中删除重复项(完美工作)

      let optionList = [];var dataArr = this.state.itemArray.map(item => {return [item.name, item]});var maparr = new Map(dataArr);
    var results = [...maparr.values()];
    if (results.length > 0) {results.map(data => {if (data.lead_owner !== null) {optionList.push({ label: data.name, value:data.name });}return true;});}console.log(optionList)

在这里,我发现了一个简单的解决方案,用于使用Reduce方法从对象数组中删除重复项。我根据对象的位置键过滤元素

const med = [{name: 'name1', position: 'left'},{name: 'name2', position: 'right'},{name: 'name3', position: 'left'},{name: 'name4', position: 'right'},{name: 'name5', position: 'left'},{name: 'name6', position: 'left1'}]
const arr = [];med.reduce((acc, curr) => {if(acc.indexOf(curr.position) === -1) {acc.push(curr.position);arr.push(curr);}return acc;}, [])
console.log(arr)

您可以使用SetFilter方法来完成此操作,

var arrObj = [{a: 1,b: 2}, {a: 1,b: 1}, {a: 1,b: 2}];
var duplicateRemover = new Set();
var distinctArrObj = arrObj.filter((obj) => {if (duplicateRemover.has(JSON.stringify(obj))) return false;duplicateRemover.add(JSON.stringify(obj));return true;});
console.log(distinctArrObj);

Set是原始类型的唯一集合,因此不能直接作用于对象,但是JSON.stringify会将其转换为原始类型,即String

如果您想仅根据某些特定键删除重复项,例如key,您可以将JSON.stringify(obj)替换为obj.key

为懒惰的打字稿开发人员提供快速(更少的运行时)和类型安全的答案:

export const uniqueBy = <T>( uniqueKey: keyof T, objects: T[]): T[] => {const ids = objects.map(object => object[uniqueKey]);return objects.filter((object, index) => !ids.includes(object[uniqueKey], index + 1));}

一个带Map的衬里(高性能,不保留顺序)

在数组arr中找到唯一的id

const arrUniq = [...new Map(arr.map(v => [v.id, v])).values()]

如果顺序很重要,请检查带有过滤器的解决方案:带过滤器的溶液


数组arr中的多个属性(placename)唯一

const arrUniq = [...new Map(arr.map(v => [JSON.stringify([v.place,v.name]), v])).values()]

数组arr中的所有属性都是唯一的

const arrUniq = [...new Map(arr.map(v => [JSON.stringify(v), v])).values()]

保留数组arr中的第一个匹配项

const arrUniq = [...new Map(arr.slice().reverse().map(v => [v.id, v])).values()].reverse()

这是一个带有Set和一些闭包的单循环方法,以防止在函数声明之外使用声明的变量并获得简短的外观。

constarray = [{ place: "here", name: "stuff", n: 1 }, { place: "there", name: "morestuff", n: 2 }, { place: "there", name: "morestuff", n: 3 }],keys = ['place', 'name'],unique = array.filter((s => o => (v => !s.has(v) && s.add(v))(keys.map(k => o[k]).join('|')))(new Set));
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }

我们可以利用JavaScript的Set对象和Array的Filter函数:例如:

// Example Arrayconst arr = [{ id: '1' }, { id: '2' }, { id: '1' }];// Gather Unique Element Id's based on which you want to filter the elements.const uniqIds = arr.reduce((ids, el) => ids.add(el.id), new Set());// Filter out uniq elements.const uniqElements = arr.filter((el) => uniqIds.delete(el.id));
console.log(uniqElements);

您可以使用for循环和条件使其独特

const data = [{ id: 1 },{ id: 2 },{ id: 3 },{ id: 4 },{ id: 5 },{ id: 6 },{ id: 6 },{ id: 6 },{ id: 7 },{ id: 8 },{ id: 8 },{ id: 8 },{ id: 8 }];
const filtered= []
for(let i=0; i<data.length; i++ ){let isHasNotEqual = truefor(let j=0; j<filtered.length; j++ ){if (filtered[j].id===data[i].id){isHasNotEqual=false}}if (isHasNotEqual){filtered.push(data[i])}}console.log(filtered);
/*output[ { id: 1 },{ id: 2 },{ id: 3 },{ id: 4 },{ id: 5 },{ id: 6 },{ id: 7 },{ id: 8 } ]
*/







这就是我的解决方案,将实际数组添加到键值对象中,其中键将是唯一标识,值可以是对象或整个对象的任何属性。

说明:具有重复项的主数组将转换为键/值对象如果Id已经存在于唯一对象中,则该值将被覆盖。最后,只需将唯一对象转换为数组。

getUniqueItems(array) {const unique = {};// here we are assigning item.name but it could be a complete object.array.map(item => unique[item.Id] = item.name);// here you can transform your array item like {text: unique[key], value: key} but actually you can do what ever you wantreturn Object.keys(unique).map(key => ({text: unique[key], value: key}));}));}

TypeScript函数将数组过滤为其唯一元素,其中唯一性由给定谓词函数决定:

function uniqueByPredicate<T>(arr: T[], predicate: (a: T, b: T) => boolean): T[] {return arr.filter((v1, i, a) => a.findIndex(v2 => predicate(v1, v2)) === i);}

没有打字:

function uniqueByPredicate(arr, predicate) {return l.filter((v1, i, a) => a.findIndex(v2 => predicate(v1, v2)) === i);}

如果数组包含对象,那么您可以使用它来删除重复的

const persons= [{ id: 1, name: 'John',phone:'23' },{ id: 2, name: 'Jane',phone:'23'},{ id: 1, name: 'Johnny',phone:'56' },{ id: 4, name: 'Alice',phone:'67' },];const unique = [...new Map(persons.map((m) => [m.id, m])).values()];

如果在电话的基础上删除重复项,只需将m.id替换为m.phone

const unique = [...new Map(persons.map((m) => [m.phone, m])).values()];