_.difference([], [])
当我有原始类型数据(如
)时,此方法可以正常工作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}];
似乎不起作用
答案 0 :(得分:53)
尝试使用此尺寸来查找对象数组的差异:
var test = [{a: 1},{b: 2}];
var test2 = [{a: 1}];
_.filter(test, function(obj){ return !_.findWhere(test2, obj); });
答案 1 :(得分:29)
虽然接受的答案是正确的,而其他答案也提供了好的想法,但还有一个额外的选项很容易用下划线来实现。
此解决方案依赖于具有唯一ID的每个对象,但在许多情况下这将是正确的,并且您可以在两行代码中获得两个对象数组的差异。
使用下划线的“pluck”方法,您可以快速构建源集和目标集中所有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; });
当然,这种技术可以扩展用于任何数组方法。
答案 2 :(得分:13)
原因很简单,具有相同内容的对象不是相同的对象,例如。
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
,因此除非它们指向同一个对象,否则不会找到对象。
您可以通过循环浏览所有项目并调用比较回调来改进下划线_.contains
,您应该能够传递给差异或包含函数,或者您可以检查this version which improves contains methods
答案 3 :(得分:3)
我实际上可以想象我宁愿使用@ kontr0l方法的情况,但你必须明白这种方法是二次的,所以基本上这个代码是天真方法的抽象 - 迭代两个数组中的所有值。
有些方法比二次方更好,我不会在这里使用任何大的O符号,但这里有两种主要的方法,两者都比天真的更好:
如前所述,如果您使用difference
方法的一些更灵活的模拟重新实现标准indexOf
方法,则可以对对象采用第一种方法。
采用第二种方法,我们可以碰到这样一个事实:截至2015年2月,只有现代浏览器支持Sets。对于javascript中的哈希(井,对象),它们只能有字符串类型的键,因此任何首先作为键调用的对象都应通过toString
方法进行转换。所以,我们需要提供一些=> correspondece。在大多数情况下的实践中,它非常简单,例如,对于您的特定示例,此类通信可以只是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})
但是买入承认稍微严格的限制 - 我们可以建立我们的设置对象和自然数之间的对应关系,我们可以构建更高效的算法,即我们所有的id都是非负整数 - 我们可以使用更有效的算法。
诀窍是通过以这种方式引入两个辅助数组来实现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();
}
因此,依靠您正在工作的数据结构有时可以帮助您。
答案 4 :(得分:3)
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)
答案 5 :(得分:1)
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);
答案 6 :(得分:0)
请原谅我在这里迟到,但这可能会有所帮助:
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}
)
)
答案 7 :(得分:0)
除非我错过了什么,否则不明白为什么这些答案如此复杂?
var a = [{'id':1, 'value':10}, {'id':2, 'value':20}];
var b = [{'id':1, 'value':10}, {'id':4, 'value':40}];
// Or use lodash _.differenceBy
const difference = (array1, array2, prop = 'id') =>
array1.filter(item1 =>
!array2.some(item2 =>
item2[prop] === item1[prop],
),
);
// In one array.
console.log(difference(a, b));
// Intersection.
console.log([...difference(a, b), ...difference(b, a)]);