使用Underscore for Java删除重复的对象


124

我有这种数组:

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

我想将其过滤为:

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

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


请发表您的代码,以及
Chetter Hummin

是否{ "a" : "2" }存在?如果是这样,是属性还是使其唯一的值?
马特

是的,我确实有一个属性作为键,我实现了有人向我展示的另一个主题下的索引,但是后来我想使用一些公共库来清理我的代码
2012年

1
请更改接受答案。
Vadorequest

Answers:


232

.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显示用法

另一个例子: 使用回调从列表中提取汽车颜色


false不需要_.uniq()。同样在lodash中,您可能会这样编写它_.uniq(a, 'a');,因为它将属性赋给a对象。
拉里·

仅当您传递isSorted的值(例如_.uniq(a, false, 'a'))时,“'.. pluck'回调速记”才有效(例如)。因此,如果您不使用功能,请确保您拥有最新的功能。对于下划线,这可能不是问题。
Shanimal

2
迭代器听起来不像是一个好名字,它就像一个类似于哈希的函数,它将确定每个对象的身份
Juan Mendes

编辑使用回调与lodash docs更加一致:)
Shanimal

1
您在jsbin上的示例可以进行更新。(1)品牌:_(cars).uniq('make')。map('make')。valueOf()AND(2)颜色:_(cars).uniq('color')。map('color' )。的价值()。您可以使颜色成熟并封闭。(所有这些,如果您升级了de lodash都会使用)
Vitor Tyburski 2014年

38

如果您要根据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。但是,确实如此。
gunwin

17

实施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
Shanimal 2013年

1
您拥有正确的键但顺序不同会破坏实现。但是我不确定为什么a当可能存在不包含key的重复对象时,为什么只检查每个对象的key a。但是,如果它a是唯一的ID ,那将是有道理的。
拉里·巴特

当我回答这个问题时,我觉得问题的重点是超越(a ==(=) b when a = b = {a:1})。我的答案是迭代器。我试着回答而不必担心动机,这可能是什么,对吗?(例如,也许他们想从演出中的汽车列表中提取品牌列表,颜色。jsbin.com/evodub/2/edit)干杯!
Shanimal

我还认为,当有人提出问题的动机时,它可以帮助我们给出简洁的答案。这是一场比赛,因此我更愿意排在第一位,并在必要时进行澄清。快乐圣帕特里克节。
Shanimal

好吧,我只是提出了另一个反对意见,因为这回答了我关于比较嵌套数组的问题。只在寻找如何覆盖iterator
nevi_me 2013年

15

当我有一个属性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}]


10

这是一个简单的解决方案,它使用深层对象比较来检查重复项(而无需求助于转换为JSON,这效率低下又很笨拙)

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在两个对象之间进行优化的深度比较,有关更多信息,请参见下划线isEqual文档

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


不依赖于具有预定义的唯一属性吗?我喜欢。
Don McCurdy 2014年

1
对于小型对象数组而言,一个好的解决方案是一个循环,而在循环中的循环与提供uniq id相比是昂贵的。
penner '16


7

尝试迭代器功能

例如,您可以返回第一个元素

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

_.uniq(x,false,function(i){  

   return i[0]   //'a','b'

})

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


seconds参数实际上是可选的,您也可以这样做_.uniq(x,function(i){ return i[0]; });
jakecraige 2013年

3

这是我的解决方案(咖啡):

_.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 ] ]

3

下划线的我不得不在iteratee函数中使用String()

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

0

我想以一种简单的编写方式来解决这个简单的解决方案,但要花一点点的计算费用……但这不是具有最小变量定义的琐碎解决方案,对吗?

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

0
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]; 
    }
);

3
欢迎来到stackoverflow。除了提供的代码外,请尝试说明为什么以及如何解决此问题。
jtate

好决定。谢谢。更新了它的工作方式细分。
凯利·比格利

-5

您可以通过以下快捷方式完成:

_.uniq(foo, 'a')


您的解决方案不适用于对象数组,而仅适用于数组
Toucouleur
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.