【问题标题】:Removing duplicate objects with Underscore for Javascript使用 Javascript 下划线删除重复对象
【发布时间】:2012-03-29 10:49:26
【问题描述】:

我有这种数组:

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];

我想过滤它有:

var bar = [ { "a" : "1" }, { "b" : "2" }];

我尝试使用_.uniq,但我猜是因为{ "a" : "1" } 不等于它自己,所以它不起作用。有什么方法可以为下划线 uniq 提供覆盖的 equals 函数?

【问题讨论】:

  • 请同时发布您的代码
  • { "a" : "2" } 这样的东西存在吗?如果是,是属性还是值使它独一无二?
  • 是的,我确实有一个属性作为键,我实现了有人在另一个主题上向我展示的索引,但后来我想使用一些常用库清理我的代码
  • 请更改已接受的答案。

标签: javascript json underscore.js


【解决方案1】:

.uniq/.unique 接受回调

var list = [{a:1,b:5},{a:1,c:5},{a:2},{a:3},{a:4},{a:3},{a:2}];

var uniqueList = _.uniq(list, function(item, key, a) { 
    return item.a;
});

// uniqueList = [Object {a=1, b=5}, Object {a=2}, Object {a=3}, Object {a=4}]

注意事项:

  1. 用于比较的回调返回值
  2. 具有唯一返回值的第一个比较对象用作唯一的
  3. underscorejs.org 演示没有回调用法
  4. lodash.com 显示使用情况

另一个例子: using the callback to extract car makes, colors from a list

【讨论】:

  • _.uniq() 不需要 false。同样在 lodash 中,您可以像 _.uniq(a, 'a'); 那样写它,因为它会在对象上提取属性 a
  • “'_.pluck' 回调速记”仅在您为 isSorted 传递值时才有效(例如 _.uniq(a, false, 'a'))我 ping 了 github/bestiejs/lodash,他们说问题已解决。因此,如果您不使用功能,请确保您拥有最新的功能。这可能不是下划线的问题。
  • Iterator 听起来不是个好名字,它是一个类似于哈希的函数,用于确定每个对象的身份
  • 编辑使用回调与 lodash 文档更一致:)
  • 您在jsbin 的示例可以有更新。 (1) 制作:_(cars).uniq('make').map('make').valueOf() AND (2) 颜色:_(cars).uniq('color').map('color' )。的价值()。您可以使颜色成熟并关闭。 (所有如果你升级 de lodash 使用)
【解决方案2】:

如果您希望根据 id 删除重复项,您可以执行以下操作:

var res = [
  {id: 1, content: 'heeey'},
  {id: 2, content: 'woah'}, 
  {id: 1, content:'foo'},
  {id: 1, content: 'heeey'},
];
var uniques = _.map(_.groupBy(res,function(doc){
  return doc.id;
}),function(grouped){
  return grouped[0];
});

//uniques
//[{id: 1, content: 'heeey'},{id: 2, content: 'woah'}]

【讨论】:

  • 当唯一标识符为 Date 时,接受的答案不起作用。但是确实如此。
【解决方案3】:

Shiplu 答案的实现。

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];

var x = _.uniq( _.collect( foo, function( x ){
    return JSON.stringify( x );
}));

console.log( x ); // returns [ { "a" : "1" }, { "b" : "2" } ]

【讨论】:

  • 顺便说一句,你是怎么得到 4 票的?要获得结果的属性,您必须将每个数组值还原回一个对象。 JSON.parse(x[0]).a 之类的东西,因为 x 不是对象数组,而是字符串数组。此外,如果您将 b 值添加到唯一值并反转 a/b 的顺序,则您的函数不再认为它们是唯一的。 (例如 `"{\"a\":\"1\",\"b\":2}" != "{\"b\":2,\"a\":\"1\"} ") 也许我错过了一些东西,但结果至少不应该有用吗?这是一个jsbin来说明jsbin.com/utoruz/2/edit
  • 您是对的,具有相同键但顺序不同的条件会破坏实现。但是我不确定为什么您只检查每个对象的键 a,而可能存在不包含键 a 的重复对象。但是,如果 a 是一个唯一的 id,那将是有意义的。
  • 当我回答这个问题时,在我看来问题的重点是覆盖(a ==(=) b when a = b = {a:1})。我的答案的重点是迭代器。我试着在不担心动机的情况下回答,这可能是什么,对吧? (例如,也许他们想从节目中的汽车列表中提取品牌、颜色列表。jsbin.com/evodub/2/edit)干杯!
  • 另外,我认为当有人提出问题提供动机时,它有助于我们给出简洁的答案。这是一场比赛,所以我更愿意成为第一个并在必要时澄清。圣帕特里克节快乐。
  • 好吧,我刚刚又投了一个赞成票,因为这回答了我关于比较嵌套数组的问题。只是在寻找如何覆盖iterator
【解决方案4】:

当我有一个属性 id 时,这是我首选的下划线方式:

var x = [{i:2}, {i:2, x:42}, {i:4}, {i:3}];
_.chain(x).indexBy("i").values().value();
// > [{i:2, x:42}, {i:4}, {i:3}]

【讨论】:

    【解决方案5】:

    使用underscore unique lib 以下对我有用,我根据_id 使列表唯一,然后返回_id 的字符串值:

    var uniqueEntities = _.uniq(entities, function (item, key, a) {
                                        return item._id.toString();
                                    });
    

    【讨论】:

      【解决方案6】:

      这是一个简单的解决方案,它使用深度对象比较来检查重复项(不求助于转换为 JSON,效率低下且 hacky)

      var newArr = _.filter(oldArr, function (element, index) {
          // tests if the element has a duplicate in the rest of the array
          for(index += 1; index < oldArr.length; index += 1) {
              if (_.isEqual(element, oldArr[index])) {
                  return false;
              }
          }
          return true;
      });
      

      如果数组后面有重复元素,它会过滤掉所有元素 - 这样会保留最后一个重复元素。

      重复测试使用_.isEqual,它在两个对象之间执行优化的深度比较,请参阅underscore isEqual documentation了解更多信息。

      编辑:更新为使用_.filter,这是一种更简洁的方法

      【讨论】:

      • 不依赖于预定义的唯一属性?我喜欢它。
      • 对于小对象数组的一个很好的解决方案,但与提供 uniq id 相比,循环中的循环代价高昂。
      【解决方案7】:

      lodash 4.6.1 文档有此作为对象键相等的示例:

      _.uniqWith(objects, _.isEqual);

      https://lodash.com/docs#uniqWith

      【讨论】:

        【解决方案8】:

        试试迭代器函数

        例如你可以返回第一个元素

        x = [['a',1],['b',2],['a',1]]
        
        _.uniq(x,false,function(i){  
        
           return i[0]   //'a','b'
        
        })
        

        => [['a',1],['b',2]]

        【讨论】:

        • 秒参数其实是可选的,你也可以_.uniq(x,function(i){ return i[0]; });
        【解决方案9】:

        这是我的解决方案(coffeescript):

        _.mixin
          deepUniq: (coll) ->
            result = []
            remove_first_el_duplicates = (coll2) ->
        
              rest = _.rest(coll2)
              first = _.first(coll2)
              result.push first
              equalsFirst = (el) -> _.isEqual(el,first)
        
              newColl = _.reject rest, equalsFirst
        
              unless _.isEmpty newColl
                remove_first_el_duplicates newColl
        
            remove_first_el_duplicates(coll)
            result
        

        示例:

        _.deepUniq([ {a:1,b:12}, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ],[ 2, 1, 2, 1 ], {a:1,b:12} ]) 
        //=> [ { a: 1, b: 12 }, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ] ]
        

        【讨论】:

          【解决方案10】:

          underscore 我不得不在 iteratee 函数中使用 String()

          function isUniq(item) {
              return String(item.user);
          }
          var myUniqArray = _.uniq(myArray, isUniq);
          

          【讨论】:

            【解决方案11】:

            我想以一种直截了当的写作方式来解决这个简单的解决方案,但会带来一点计算费用的痛苦……但这不是一个具有最小变量定义的简单解决方案吗?

            function uniq(ArrayObjects){
              var out = []
              ArrayObjects.map(obj => {
                if(_.every(out, outobj => !_.isEqual(obj, outobj))) out.push(obj)
              })
              return out
            }
            

            【讨论】:

              【解决方案12】:
              var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
              var bar = _.map(_.groupBy(foo, function (f) { 
                      return JSON.stringify(f); 
                  }), function (gr) { 
                      return gr[0]; 
                  }
              );
              

              让我们分解一下。首先让我们按照字符串化的值对数组项进行分组

              var grouped = _.groupBy(foo, function (f) { 
                  return JSON.stringify(f); 
              });
              

              grouped 看起来像:

              {
                  '{ "a" : "1" }' = [ { "a" : "1" } { "a" : "1" } ],
                  '{ "b" : "2" }' = [ { "b" : "2" } ]
              }
              

              然后让我们从每个组中获取第一个元素

              var bar = _.map(grouped, function(gr)
                  return gr[0]; 
              });
              

              bar 看起来像: [ { "a" : "1" }, { "b" : "2" } ]

              把它们放在一起:

              var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
              var bar = _.map(_.groupBy(foo, function (f) { 
                      return JSON.stringify(f); 
                  }), function (gr) { 
                      return gr[0]; 
                  }
              );
              

              【讨论】:

              • 欢迎来到stackoverflow。除了您提供的代码之外,请尝试解释一下为什么以及如何解决此问题。
              • 好电话。谢谢。更新了它的工作原理。
              【解决方案13】:

              你可以简写为:

              _.uniq(foo, 'a')

              【讨论】:

              • 您的解决方案不适用于对象数组,而仅适用于数组
              猜你喜欢
              • 2014-03-19
              • 1970-01-01
              • 2012-09-13
              • 2015-05-05
              • 2016-05-14
              • 2015-02-26
              • 1970-01-01
              • 1970-01-01
              • 2023-03-28
              相关资源
              最近更新 更多