Javascript 使用下划线';s&x201C;差异”;对象数组上的方法

Javascript 使用下划线';s&x201C;差异”;对象数组上的方法,javascript,underscore.js,Javascript,Underscore.js,当我使用诸如 _.difference([], []) 而\差分(a,b)调用返回[1,3,4] 但如果我用的是像 var a = [1,2,3,4]; var b = [2,5,6]; 似乎不起作用原因很简单,具有相同内容的对象不是相同的对象 var a = [{'id':1, 'value':10}, {'id':2, 'value':20}]; var b = [{'id':1, 'value':10}, {'id':4, 'value':40}]; 它不会返回0,而是返回-1,因为

当我使用诸如

_.difference([], [])
\差分(a,b)
调用返回
[1,3,4]

但如果我用的是像

var a = [1,2,3,4];
var b = [2,5,6];

似乎不起作用

原因很简单,具有相同内容的对象不是相同的对象

var a = [{'id':1, 'value':10}, {'id':2, 'value':20}];
var b = [{'id':1, 'value':10}, {'id':4, 'value':40}];
它不会返回0,而是返回-1,因为我们正在搜索其他对象

请参阅源代码,
差异
使用
包含

var a = [{'id':1, 'value':10}, {'id':2, 'value':20}]; 
a.indexOf({'id':1, 'value':10})
。.contains
最终使用
索引
,因此不会找到对象,除非它们指向同一个对象


您可以通过在所有项之间循环并调用比较回调来改进下划线
\uu.contains
,您应该能够将该回调传递给difference或contains函数,或者您可以检查以查看查找对象数组差异的大小:

_.difference = function(array) {
  var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
  return _.filter(array, function(value){ return !_.contains(rest, value); });
};

虽然被接受的答案是正确的,其他答案也给出了很好的想法,但还有一个附加选项很容易用下划线实现

这个解决方案依赖于每个对象都有一个唯一的ID,但在许多情况下这是正确的,并且您可以在两行代码中获得两个对象数组的差异

使用下划线的“pull”方法,可以快速构造源集中和目标集中所有ID的数组。从此,下划线的所有数组方法都将起作用,如差、并、交等

操作完成后,从源列表中获取所需的对象列表非常简单。下面是一个例子:

冗长的:

var test = [{a: 1},{b: 2}];
var test2 = [{a: 1}];

_.filter(test, function(obj){ return !_.findWhere(test2, obj); });
或者,更简洁地说:

var a = [{'id':1, 'value':10}, {'id':2, 'value':20}];
var b = [{'id':1, 'value':10}, {'id':4, 'value':40}];

var arr1 = _.pluck(a, "id");
var arr2 = _.pluck(b, "id");
var diff = _.difference(arr1, arr2);
var result = _.filter(a, function(obj) { return diff.indexOf(obj.id) >= 0; });

当然,同样的技术也可以扩展到任何数组方法。

请原谅我在这里晚些时候跳进来,但这可能会有所帮助:

var diff = _.difference(_.pluck(a, "id"), _.pluck(b, "id"));
var result = _.filter(a, function(obj) { return diff.indexOf(obj.id) >= 0; });

实际上,我可以想象我宁愿使用@kontr0l方法而不是其他方法的情况,但是您必须理解这种方法是二次的,所以基本上这段代码是对天真方法的抽象——在两个数组中迭代所有值

有比二次型更好的方法,我不会在这里使用任何大O符号,但这里有两种主要方法,都比幼稚的方法更好:

  • 遍历其中一个数组,并使用二进制搜索检查排序后的第二个数组中是否存在
  • 将值放入set/hash/dictionary/you name中
如前所述,如果您使用更灵活的
indexOf
方法来重新实现标准
difference
方法,则可以对对象采用第一种方法

使用第二种方法,我们可能会遇到这样一个事实:截至2015年2月,只有现代浏览器支持。对于javascript中的散列(对象),它们只能有字符串类型的键,因此任何作为键调用的对象都应该首先通过
toString
方法进行转换。因此,我们需要提供一些=>通信。在实践中,在大多数情况下,这是非常简单的,例如,对于您的特定示例,这样的通信可以是
String(obj.id)

有了这样的对应关系,我们还可以使用以下lodas/undercore方法:

array_of_objects = 
    // return the non-matching items (without the expected properties)
    _.difference(array_of_objects,
        // filter original list for items with expected properties
        _.where(
            // original list
            array_of_objects,
            // expected properties
            {'id':1, 'value':10}
        )
    )
但是,我们承认稍微严格一些的限制——我们可以在集合对象和自然数之间建立对应关系——我们可以建立更有效的算法,也就是说,我们所有的ID都是非负整数——我们可以使用更有效的算法

诀窍是通过以下方式引入两个助手数组来实现set:

var idsA = _.pluck(a, 'id');
var idsB = _.pluck(b, 'id');

// actually here we can stop in some cases, because 
// quite often we need to identify object, but not the object itself - 
// for instance to send some ids through remote API.
var intersect = _.intersection(idsA, idsB);

//to be 100% sure you get the idea, here we assume that object having equal ids are treated as equal, so does not really matter which of arrays we'll iterate:

var dictA = _.object(idsA, a); // now we can find a by id faster then with _.find
var intersectObj = intersect.map(function(id) {return dictA[id})
最后,我们可以介绍交叉点:

var set = function (arr, valueOf) {
    var natSet = naturalSet(arr.map(valueOf));
    return {
        contains: function (item) {
            return natSet.contains(valueOf(item))
        },
        toArray: function () {
            var sparse = natSet._getSparse();
            var res = natSet._getDense().map(function (i) {
                return arr[sparse[i]];
            });
            return res;
        }
    }
}

因此,依赖于您正在处理的数据结构有时会对您有所帮助。

除非我遗漏了什么,否则您不明白为什么这些答案如此复杂吗

var intersection = function(arr1, arr2, valueOf) {
   return set(arr2.filter(set(arr1, valueOf).contains), valueOf).toArray();
}
var a=[{'id':1,'value':10},{'id':2,'value':20}];
变量b=[{'id':1,'value':10},{'id':4,'value':40}];
//或者使用lodash u.differenceBy
常量差=(array1,array2,prop='id')=>
数组1.过滤器(项1=>
!array2.some(项目2=>
项目2[prop]==项目1[prop],
),
);
//在一个数组中。
控制台日志(差异(a,b));
//十字路口。

log([…差异(a,b),…差异(b,a)]有没有办法让它将对象与它的value@Nas请参阅编辑或检查此缩进代码,方法是在代码后面加4个空格或在``字符内加空格。谢谢!已经有一段时间了,你搞定了。可以(几乎?)重写为
拒绝(test),匹配(test2[0])如果您只是针对单个对象进行区分,并且如果您想按特定id进行筛选,请使用:
\uj.filter(test,function(obj){return!\uj.findWhere(test2,{id:obj.id});})与相似(不是重复),如果您来这里查找两个对象之间的差异(即它们的增量,而不是对象数组之间的差异),没有内置下划线,但您可以尝试注意到_difference(a,b)将返回[1,3,4]。u。差分方法将返回第一个数组中不在另一个数组中的元素伟大的答案,我喜欢kontr0l,但Angular喜欢向对象添加hashkey属性,因此如果要比较的对象还没有hashkey,那么比较整个对象就很有挑战性。与你的答案相比,我可以在ID上单独比较,这是一个完美的方法。警告:拔毛不存在,现在读这个你可以用了。map@maliness,澄清一下,对于lodash来说,Pull并不存在,但它仍然存在于下划线中,这就是问题所指的。欢迎!如果你解释了你的方法相对于其他答案的优势,你的答案将更有帮助(并且更有可能获得选票)。
var intersection = function(arr1, arr2, valueOf) {
   return set(arr2.filter(set(arr1, valueOf).contains), valueOf).toArray();
}
without using underscorejs,
here is the pretty simple method i got solution ... 

a = [{'key':'123'},{'key':'222'},{'key':'333'}]
b = [{'key':'123'},{'key':'222'}]

var diff = a.filter(function(item1) {
  for (var i in b) {
    if (item1.key === b[i].key) { return false; }
  };
  return true;
});
console.log('result',diff)
var a = [{'id':1, 'value':10}, {'id':2, 'value':20}];
var b = [{'id':1, 'value':10}, {'id':4, 'value':40}];

var c = _.difference(a.map(e => e.id), b.map(e =>e.id));
var array = [];
array = a.map(e => {
   if(c.includes(e.id)){
     return e;
   }
}).filter(r=>r);