如何从JavaScript数组中删除重复的OBJECTS?

时间:2016-05-26 11:42:41

标签: javascript arrays duplicates unique

从对象数组中删除重复对象的最佳方法是什么?

来自

var arr = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35},
        {"name":"Bob", "age":35},
        {"name":"Joe", "age":17}, 
    ]

删除重复项后,预期结果为

res= arr = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35},
        {"name":"Bob", "age":35},
    ]

(5个对象,1个副本,4个左侧)。

每个对象的属性数量是固定的,每个数组的属性名称都相同。但是,从数组到数组,它们可能不仅仅是上面的“名称”和“年龄”,但属性的名称可以是任何名称。

@Pointy请将上述问题中的重复单词视为语义上的“重复” - 分别具有相同属性数,相同属性和相同属性值的对象。

这不是重复的 Remove Duplicates from JavaScript Array

4 个答案:

答案 0 :(得分:3)

如果对象是否已插入,则可以使用对象进行查找。

编辑:

获取对象的所有属性并使用键值的更新。如果只应该使用一些属性,那么我建议使用带有相关键的数组,比如

['name', 'age']

并将其与

一起使用
var key = ['name', 'age'].map(function (k) { return a[k]; }).join('|');



var arr = [{ "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 }, { "name": "Bob", "age": 35 }, { "name": "Joe", "age": 17 }],
    filtered = arr.filter(function (a) {
        var key = Object.keys(a).map(function (k) { return a[k]; }).join('|');
        if (!this[key]) {
            return this[key] = true;
        }
    }, Object.create(null));

console.log(filtered);




答案 1 :(得分:1)

使用Object.keysArray.everyArray.concat函数的解决方案:

var names = {}, result = [];
arr.forEach(function (v) {
    var name = v['name'];
    names[name] = names[name] || [];
    // considering multiple objects with same 'name' but different 'age' - and vise versa
    if (!Object.keys(names[name]).length ||  
        names[name].every((obj) => ((obj['name'] === name && obj['age'] !== v['age']) || (obj['name'] !== name && obj['age'] === v['age'])) )) {
        names[name].push(v);
    }
}, names);
Object.keys(names).forEach((k) => result = result.concat(names[k]), result);

console.log(JSON.stringify(result, 0, 4));

输出:

[
    {
        "name": "Joe",
        "age": 17
    },
    {
        "name": "Bob",
        "age": 17
    },
    {
        "name": "Bob",
        "age": 35
    },
    {
        "name": "Carl",
        "age": 35
    }
]

答案 2 :(得分:0)

这是从对象数组中过滤任何平面(非嵌套)对象的副本的一般解决方案。不适合这个具体问题。否则,通过根据已知的属性和值建立LUT(例如,由Map对象构成的查找表),可以轻松完成此作业。再次..您可以将此解决方案应用于任何对象数组以删除欺骗。

执行此任务的最佳方式是Object.prototype.compare()的发明所以一旦我们掌握了它,这项工作就变成了游戏。让我们看看吧。



Object.prototype.compare = function(o){
  var ok = Object.keys(this);
  return typeof o === "object" && ok.length === Object.keys(o).length ? ok.every(k => this[k] === o[k]) : false;
};

var arr = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35},
        {"name":"Bob", "age":35},
        {"name":"Joe", "age":17}, 
    ],
    red = arr.reduce((p,c,i) => {var f = p.slice(i).findIndex(o => o.compare(p[i-1]));
                                 return f == -1 ? p : (p.splice(f+i,1),p)},arr);
console.log(JSON.stringify(arr,null,2));




我相信这是迄今为止这样做的最佳方式。我更喜欢Map或Set,但是从这个版本的ES6开始,即使我们可以使用对象作为Map对象中的键,它们仍然无法用于访问值。我的意思是即使关键对象是空对象,另一个空对象也不会定义该关键字。但我认为有一项工作正在进行,因为在Map对象中NaN可以是一个键,你可以使用NaN访问它,即使在JS世界中你都知道NaN !== NaN如;

var m = new Map();
m.set({},true);
m.set("a",1);
m.set(NaN,"cow");
m.get({},true};   // undefined
m.get("a",1);     // 1
m.get(NaN,"cow"); // "cow" so NaN == NaN is true in the Map ...

答案 3 :(得分:0)

const arr1 = [{"name":"ren","age":3,"weight":120},{"name":"ren","age":2,"weight":100},{"name":"ren","age":2,"weight":100},{"name":"ren","age":2,"weight":100},{"name":"ren","age":2,"weight":100},{"name":"ren","age":2,"weight":100},{"name":"ren","age":1,"weight":100},{"name":"stimpy","age":2,"weight":100},{"name":"george american","age":56,"weight":220}]
const arr2 = [{"name":"ren","age":2,"weight":150},{"name":"ren","age":2,"weight":150},{"name":"ren","age":2,"weight":150},{"name":"ren","age":2,"weight":100},{"name":"stimpy","age":2,"weight":100},{"name":"ren","age":3,"weight":100},{"name":"stimpy","age":1,"weight":100},{"name":"ren","age":2,"weight":100},{"name":"circus midgets","age":5,"weight":200}]

function uniq_all_props (__arr1, __arr2) {
  let arr = __arr1.concat(__arr2)
  console.log('arr.length', arr.length)
  let set = []
  let result = []
  arr.forEach(function (__obj) {
    /** Set each obj to a string. */
    let string = JSON.stringify(__obj)
    set.push(string)
  })
  set.filter(function (elem, index, self) {
    /** Use filter as a loop to push onto results array.
     * This is done to preserve prop types from original arrays */
    if (index === self.indexOf(elem)) {
      result.push(arr[index])
    }
  })
  return result
}


console.log(uniq_all_props(arr1, arr2))