如何在对象上使用下划线的“交集”?

_.intersection([], []) 

只适用于原始types,对不对?

它不适用于对象。 我怎样才能使它与对象(也许通过检查“ID”字段)?

 var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ] var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ] 

在这个例子中,结果应该是:

 _.intersection(a, b); 

[{'id':1,'name':'jake'}];

您可以根据下划线的function创build另一个function。 您只需更改原始函数的一行代码即可:

 _.intersectionObjects = function(array) { var slice = Array.prototype.slice; // added this line as a utility var rest = slice.call(arguments, 1); return _.filter(_.uniq(array), function(item) { return _.every(rest, function(other) { //return _.indexOf(other, item) >= 0; return _.any(other, function(element) { return _.isEqual(element, item); }); }); }); }; 

在这种情况下,您现在将使用下划线的isEqual()方法,而不是JavaScript的相等比较器。 我试着用你的例子,它的工作。 下面是关于isEqual函数的下划线文档摘录:

 _.isEqual(object, other) Performs an optimized deep comparison between the two objects, to determine if they should be considered equal. 

你可以在这里find文档: http : //documentcloud.github.com/underscore/#isEqual

我把代码放在jsFiddle上,所以你可以testing并确认它: http : //jsfiddle.net/luisperezphd/jrJxT/

这是另一种algorithm,应该灵活,性能更好。 其中一个改进就是你可以指定你自己的比较函数,所以在你的情况下你可以比较这个id是否是一个唯一的标识符。

 function intersectionObjects2(a, b, areEqualFunction) { var results = []; for(var i = 0; i < a.length; i++) { var aElement = a[i]; var existsInB = _.any(b, function(bElement) { return areEqualFunction(bElement, aElement); }); if(existsInB) { results.push(aElement); } } return results; } function intersectionObjects() { var results = arguments[0]; var lastArgument = arguments[arguments.length - 1]; var arrayCount = arguments.length; var areEqualFunction = _.isEqual; if(typeof lastArgument === "function") { areEqualFunction = lastArgument; arrayCount--; } for(var i = 1; i < arrayCount ; i++) { var array = arguments[i]; results = intersectionObjects2(results, array, areEqualFunction); if(results.length === 0) break; } return results; } 

你可以像这样使用它:

 var a = [ { id: 1, name: 'jake' }, { id: 4, name: 'jenny'} ]; var b = [ { id: 1, name: 'jake' }, { id: 9, name: 'nick'} ]; var c = [ { id: 1, name: 'jake' }, { id: 4, name: 'jenny'}, { id: 9, name: 'nick'} ]; var result = intersectionObjects(a, b, c, function(item1, item2) { return item1.id === item2.id; }); 

或者你可以省略函数,它会使用下划线_.isEqual()函数,如下所示:

 var result = intersectionObjects(a, b, c); 

你可以在jsFiddle上find它: http : //jsfiddle.net/luisperezphd/43vksdn6/

下划线中的数组方法非常强大,您只需要几行即可完成您想要的操作:

 var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ]; var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ]; var result = _(a).chain().map(function(ea) { return _.find(b, function(eb) {return ea.id == eb.id;}); }).compact().value(); 

如果你有大的数组,你可以用另外一行代替compact()调用:

 var result = []; _.each(a, function(ea) { var entry = _.find(b, function(eb) {return ea.id == eb.id;}); if (entry) result.push(entry); }); 

我想分享一下我的一般解决scheme。

我添加了一个通用函数来强调,使用mixin,根据给定的散列函数对两个集合执行二进制“数组”操作:

 _.mixin({ collectionOperation: function(arr1, arr2, hash, action) { var iArr1 = _(arr1).indexBy(hash) , iArr2 = _(arr2).indexBy(hash); return action(_(iArr1).keys(), _(iArr2).keys()).map(function (id) { return iArr1[id] || iArr2[id]; }); } }); 

用法示例:

 _([{id:1,v:'q'},{id:2,v:'p'}]).collectionOperation([{id:3,v:'pq'}], 'id', _.union ) 

请注意, “id”可能被replace为一个函数。

我相信这个解决scheme是O(n + m)。

从技术上讲,它可以处理对象,但是你需要小心引用的平等。

 var jake = {'id': 1, 'name': 'jake' }, jenny = {'id':4, 'name': 'jenny'}, nick = {'id': 9, 'name': 'nick'}; var a = [jake, jenny] var b = [jake, nick]; _.intersection(a, b); // is [jake] 

在lodash 4.0.0。 我们可以试试这个

 var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ]; var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ]; _.intersectionBy(a, b, 'id'); 

输出:

[{'id':1,'name':'jake'}];

 var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ]; var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ]; 

工作function:

  function intersection(a,b){ var c=[]; for(m in a){ for(n in b){ if((a[m].id==a[n].id)&&(a[m].name==b[n].name)) c.push(a[m]); }} return c; } console.log(intersection(a,b)); 

在Pointy的build议之后,我也专门尝试了jQuery中的代码。 比较必须根据JSON对象的结构进行定制。

 <script type="text/javascript"> jQuery(document).ready(function(){ var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ]; var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ]; var c=[]; jQuery.each(a, function(ka,va) { jQuery.each(b, function(kb,vb) { if(compare(va,vb)) c.push(va); }); }); console.log(c); }); function compare(a,b){ if(a.id==b.id&&a.name==b.name) return true; else return false; } </script> 

如果你想比较只有对象:

 b = {"1":{"prod":"fibaro"},"2":{"prod":"aeotec"},"3":{"prod":"sw"}}; a = {"1":{"prod":"fibaro"}}; _.intersectObjects = function(a,b){ var m = Object.keys(a).length; var n = Object.keys(b).length; var output; if (m > n) output = _.clone(a); else output = _.clone(b); var keys = _.xor(_.keys(a),_.keys(b)); for(k in keys){ console.log(k); delete output[keys[k]]; } return output; } _.intersectObjects(a,b); // this returns { '1': { prod: 'fibaro' } } 
 var a = {a:'a1',b:'b1'}, b = {a:'a2',b:'b2',c:'c2'}; _.pick(a,_.intersection(_.keys(a),_.keys(b))); // {a:'a1',b:'b1'}