【问题标题】:Remove duplicates in an object array Javascript删除对象数组Javascript中的重复项
【发布时间】:2016-07-02 03:02:01
【问题描述】:

我有一个对象数组

list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {x:1,y:2}]

我正在寻找一种有效的方法(如果可能的话O(log(n)))来删除重复项并最终得到

list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}]

我尝试过_.uniq 甚至_.contains,但找不到令人满意的解决方案。

谢谢!

编辑:该问题已被确定为与另一个问题重复。我在发布之前看到了这个问题,但它没有回答我的问题,因为它是一个对象数组(而不是 2-dim 数组,谢谢 Aaron),或者至少其他问题的解决方案不适用于我的情况。

【问题讨论】:

标签: javascript arrays underscore.js


【解决方案1】:

以下将起作用:

var a = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {x:1,y:2}];

var b = _.uniq(a, function(v) { 
    return v.x && v.y;
})

console.log(b);  // [ { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 } ]

【讨论】:

  • 谢谢!对我有用,比安迪的解决方案快吗?
  • 我不知道。编写的代码更少,而且下划线似乎都包含在内...@kwn
  • 除非您要处理 1000 个元素中的 10 个,否则性能应该不是问题。我想你必须权衡加载一个单独的库的成本(如果你的堆栈中没有 lodash)或者只是使用稍微冗长的 vanilla 函数。
  • 不要认为这可以正常工作,例如1 && 2 == 2 && 2
  • 如果输入是 [{x:1, y: 2}, {x: 2. y:2}] 那么结果将是 [{x:1, y:2}] -第二个对象将被删除,即使它不是重复的
【解决方案2】:

香草JS版本:

const list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {x:1,y:2}];

function dedupe(arr) {
  return arr.reduce(function(p, c) {

    // create an identifying id from the object values
    var id = [c.x, c.y].join('|');

    // if the id is not found in the temp array
    // add the object to the output array
    // and add the key to the temp array
    if (p.temp.indexOf(id) === -1) {
      p.out.push(c);
      p.temp.push(id);
    }
    return p;

    // return the deduped array
  }, {
    temp: [],
    out: []
  }).out;
}

console.log(dedupe(list));

【讨论】:

    【解决方案3】:

    检查是否已经在O(n)中的临时对象后过滤数组。

    var list = [{ x: 1, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 }, { x: 1, y: 2 }],
        filtered = function (array) {
            var o = {};
            return array.filter(function (a) {
                var k = a.x + '|' + a.y;
                if (!o[k]) {
                    o[k] = true;
                    return true;
                }
            });
        }(list);
    
    document.write('<pre>' + JSON.stringify(filtered, 0, 4) + '</pre>');

    【讨论】:

      【解决方案4】:

      纯 javascript (ES2015),使用 Set

      const list = [{ x: 1, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 }, { x: 1, y: 2 }];
      
      const uniq = new Set(list.map(e => JSON.stringify(e)));
      
      const res = Array.from(uniq).map(e => JSON.parse(e));
      
      document.write(JSON.stringify(res));

      【讨论】:

      • stringifyparse 看起来并不是实现这一目标的最佳方式。
      • 在 ES2015 中编写代码时不应该使用 var!
      • @AminJafari 即使在 2020 年也没有使用 var。只要注意范围,var 绝对没问题。虽然这个答案不是最高效的,但它可以按照 OP 的问题工作
      • @SeaWarrior404 我知道,这就是我投票的原因:) 在可以使用 const 的地方使用 var 并不是一个好习惯
      【解决方案5】:

      我会将Arrayr.prototype.reduceArrayr.prototype.some 方法与展开运算符结合使用。

      1.显式解决方案。基于数组对象包含的完整知识。

      list = list.reduce((r, i) => 
        !r.some(j => i.x === j.x && i.y === j.y) ? [...r, i] : r
      , [])
      

      这里我们对比较对象结构有严格的限制:{x: N, y: M}。而[{x:1, y:2}, {x:1, y:2, z:3}] 将被过滤为[{x:1, y:2}]

      2。通用解决方案,JSON.stringify()。被比较的对象可以有任意数量的任意属性。

      list = list.reduce((r, i) => 
        !r.some(j => JSON.stringify(i) === JSON.stringify(j)) ? [...r, i] : r
      , [])
      

      这种方法对属性顺序有限制,所以[{x:1, y:2}, {y:2, x:1}]不会被过滤。

      3。通用解决方案,Object.keys()。顺序无关紧要。

      list = list.reduce((r, i) => 
        !r.some(j => !Object.keys(i).some(k => i[k] !== j[k])) ? [...r, i] : r
      , [])
      

      此方法还有另一个限制:比较对象必须具有相同的键列表。 因此,[{x:1, y:2}, {x:1}] 将被过滤,尽管存在明显差异。

      4.通用解决方案,Object.keys() + .length

      list = list.reduce((r, i) => 
        !r.some(j => Object.keys(i).length === Object.keys(j).length 
          && !Object.keys(i).some(k => i[k] !== j[k])) ? [...r, i] : r
      , [])
      

      最后一种方法是通过键的数量、键本身和键值来比较对象。

      我创建了一个Plunker 来玩它。

      【讨论】:

      • 您能否解释一下第 4 种方法中发生了什么,尤其是数组部分和一些比较?理解起来有点密集
      • @SeaWarrior404 4 方法是键/值比较的组合,表示为从 p.3 中提取的第二个“some”和表示为第一个“some”的长度比较,它迭代地比较初始数组中每个对象的键以及初始数组中所有其他对象的键的长度,以确保列表中的所有项目具有相同数量的字段。如果给定对象与列表中的其他对象具有相同数量的字段,它将被发送到键值比较(第二个“一些”)。如果没有,它会立即被过滤掉。
      • 您不需要在每次迭代时重新创建数组。您可以改用r.push(i)if (!r.some(j =&gt; JSON.stringify(i) === JSON.stringify(j))) r.push(i); return r
      • 为通用解决方案点赞,正是我所需要的!
      【解决方案6】:

      尝试使用以下方法:

      list = list.filter((elem, index, self) => self.findIndex(
          (t) => {return (t.x === elem.x && t.y === elem.y)}) === index)
      

      【讨论】:

      【解决方案7】:

      一个适用于 ES6+ 的内衬

      如果你想通过 x 和 y 找到 uniq:

      arr.filter((v,i,a)=>a.findIndex(t=>(t.x === v.x && t.y===v.y))===i)
      

      如果您想按所有属性查找唯一性:

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

      【讨论】:

        【解决方案8】:

        使用 lodash 你可以使用这个单线:

         _.uniqBy(list, e => { return e.x && e.y })
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-10-25
          • 2013-01-17
          • 2012-11-24
          • 2017-09-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多