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

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

当前回答

您也可以使用地图:

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

其他回答

我认为,将reduce与JSON.stringify结合起来以完美地比较对象,并选择性地添加那些尚未在累加器中的对象是一种优雅的方式。

请记住,在极端情况下,JSON.stringify可能会成为一个性能问题,因为阵列有许多对象,而且它们很复杂,但在大多数情况下,这是IMHO的最短路径。

var集合=〔{a:1},{a:2},{a:1},{a:3}〕var filtered=collection.reduce((已过滤,项)=>{if(!filtered.some(filteredItem=>JSON.stringify(filtered item)==JSON.sstringify(item)))已过滤推送(项)返回已过滤}, [])console.log(已过滤)

另一种写法相同(但效率较低):

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

这是我的解决方案,它基于object.prop搜索重复的对象,当找到重复的对象时,它会将array1中的值替换为array2值

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 array1
                array1[j] = array2[i]; // replace it in array1 with array2 value
                found = true;
            }
        }
        if (!found) // if item in array2 not found in array1, add it to array1
            array1.push(array2[i]);

    }
    return array1;
}

考虑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 }]

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

“消除重复项”函数通常称为unique或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 comparison
    function 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;
    }

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

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;

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