【问题标题】:How to remove duplicated OBJECTS from JavaScript array?如何从 JavaScript 数组中删除重复的对象?
【发布时间】:2016-09-24 09:38:38
【问题描述】:

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

来自

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

【问题讨论】:

  • @Alex 不。我说的是对象数组,而不是字符串或数字数组。
  • 就 JavaScript 而言,没有任何对象与任何其他对象重复。您必须设计和实施一个解决方案来比较对象并根据您自己的标准确定它们是否重复。
  • @Pointy 请将上述问题中的重复词视为口头意义上的“重复” - 对象分别具有相同数量的属性、相同的属性和相同的属性值。
  • 我很高兴至少这个问题不再被视为重复,因为我检查了几乎所有关于数组和重复的 SO 问题谢谢。

标签: javascript arrays duplicates unique


【解决方案1】:

你可以使用一个对象来查找,如果一个对象已经插入或没有。

编辑:

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

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

【讨论】:

    【解决方案2】:

    使用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
        }
    ]
    

    【讨论】:

      【解决方案3】:

      这是从对象数组中过滤任何平面(非嵌套)对象的重复项的通用解决方案。不适合这个特定的问题。否则,通过根据已知的属性和值建立 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 可以是一个键,即使在 JS 世界中,您也可以使用 NaN 访问它,因为你们都知道 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 ...
      

      【讨论】:

        【解决方案4】:
        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))
        

        【讨论】:

          【解决方案5】:

          根据ID将Array转为JSON,再转为Array。

              const json = {};
              this.data.forEach(ele => {
                json[ele['id']] = ele;
              });
              console.log(Object.values(json));
          

          【讨论】:

            猜你喜欢
            • 2021-12-30
            • 2018-08-15
            • 1970-01-01
            • 2014-06-25
            • 1970-01-01
            • 2021-12-07
            • 1970-01-01
            • 2018-06-19
            相关资源
            最近更新 更多