在对象数组上使用下划线的“差异”方法

_.difference([], []) 

这个方法工作正常,当我有像原始types的数据

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

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

但万一我使用的对象

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

似乎没有工作

原因就是具有相同内容的对象不是同一个对象,例如

 var a = [{'id':1, 'value':10}, {'id':2, 'value':20}]; a.indexOf({'id':1, 'value':10}) 

它不会返回0,而是-1,因为我们正在寻找一个不同的对象

请参阅源代码http://underscorejs.org/underscore.js,_.difference使用;_.contains

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

_.contains最终使用indexOf因此不会find对象,除非它们指向相同的对象。

您可以通过遍历所有项目并调用比较callback来改进下划线_.contains ,您应该能够传递差异或包含函数,或者您可以检查包含方法的改进版本

试试这个大小来find一个对象数组的差异:

 var test = [{a: 1},{b: 2}]; var test2 = [{a: 1}]; _.filter(test, function(obj){ return !_.findWhere(test2, obj); }); 

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

这个解决scheme依赖于每个对象都有一个唯一的ID,但是在很多情况下这是真实的,你可以用两行代码来获得两个对象数组的差异。

使用下划线的“pluck”方法,可以快速构build源数据集和目标数据集中所有ID的数组。 从那里,所有的下划线的数组方法将工作,差异,联盟,交集等…

操作之后,从源列表中获取所需对象的列表是微不足道的。 这是一个例子:

详细:

 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符号,但这里有两个主要的方法,都是更好的然后天真的一个:

  • 迭代通过其中一个数组,并使用二分查找检查是否存在于sorting的第二个数组中。
  • 把值放入set / hash / dictionary /你的名字。

正如已经提到的那样,如果使用一些更灵活的indexOf方法来实现标准的difference方法,那么对象可以采用第一种方法。

用第二种方法,我们可以打开墙,事实上,截至2015年2月,只有现代浏览器支持集 。 作为JavaScript中的散列(好,对象),它们只能有stringtypes的键,所以任何被调用为键的对象都应该通过toString方法来转换。 所以,我们需要提供一些=>相关。 在大多数情况下,实践是非常简单的,例如,对于您的特定示例,这种对应关系可以是String(obj.id)

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

 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}) 

但是,购买承认稍微严格的限制 – 我们可以build立我们的集合对象和自然数之间的对应,我们可以build立更有效的algorithm,即我们所有的ID都是非负整数 – 我们可以使用更有效的algorithm。

诀窍是通过这种方式引入两个辅助数组来实现set:

 var naturalSet = function (arr) { var sparse = []; var dense = []; var contains = function (i) { var res = sparse[i] < dense.length && dense[sparse[i]] == i; return res; } var add = function (v) { if (!contains(v)) { sparse[v] = dense.length; dense.push(v); } } arr.forEach(add); return { contains: contains, toArray: function () { return dense }, _getDense: function () { return dense }, _getSparse: function () { return sparse } } } 

然后我们可以引入set到naturalSet的映射:

 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(); } 

所以,依靠你正在工作的数据结构可以帮助你。

 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) 

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

 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} ) )