Javascript 如何在对象上使用下划线的“交集”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8672383/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use underscore's "intersection" on objects?
提问by user847495
_.intersection([], [])
only works with primitive types, right?
只适用于原始类型,对吗?
It doesn't work with objects. How can I make it work with objects (maybe by checking the "Id" field)?
它不适用于对象。我怎样才能让它与对象一起工作(也许通过检查“Id”字段)?
var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ]
var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ]
In this example, the result should be:
在这个例子中,结果应该是:
_.intersection(a, b);
[ {'id': 1, 'name': 'jake' } ];
[ {'id': 1, 'name': 'jake' } ];
采纳答案by Luis Perez
You can create another function based on underscore's function. You only have to change one line of code from the original 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); });
});
});
};
In this case you'd now be using underscore's isEqual() method instead of JavaScript's equality comparer. I tried it with your example and it worked. Here is an excerpt from underscore's documentation regarding the isEqual function:
在这种情况下,您现在将使用下划线的 isEqual() 方法而不是 JavaScript 的相等比较器。我用你的例子试过了,它奏效了。以下是下划线关于 isEqual 函数的文档的摘录:
_.isEqual(object, other)
Performs an optimized deep comparison between the two objects, to determine if they should be considered equal.
You can find the documentation here: http://documentcloud.github.com/underscore/#isEqual
您可以在此处找到文档:http: //documentcloud.github.com/underscore/#isEqual
I put up the code on jsFiddle so you can test and confirm it: http://jsfiddle.net/luisperezphd/jrJxT/
我把代码放在 jsFiddle 上,所以你可以测试和确认它:http: //jsfiddle.net/luisperezphd/jrJxT/
回答by Luis Perez
Here is an alternative algorithm that should be flexible and perform better. One of those improvements is that you can specify your own comparison function so in your case you can just compare the id if it's a unique identifier.
这是一种应该灵活且性能更好的替代算法。其中一项改进是您可以指定自己的比较函数,因此在您的情况下,如果它是唯一标识符,您可以只比较 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;
}
You can use it like this:
你可以这样使用它:
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;
});
Or you can leave out the function and it will use underscores _.isEqual() function, like so:
或者您可以省略该函数,它将使用下划线 _.isEqual() 函数,如下所示:
var result = intersectionObjects(a, b, c);
You can find it on jsFiddle here: http://jsfiddle.net/luisperezphd/43vksdn6/
你可以在 jsFiddle 上找到它:http: //jsfiddle.net/luisperezphd/43vksdn6/
回答by Julian D.
The array methods in underscore are very powerful, you should only need a few lines to accomplish what you want to do:
下划线中的数组方法非常强大,你只需要几行代码就可以完成你想做的事情:
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();
If you have large arrays you can get rid of the compact()
call with one additional line:
如果您有大型数组,您可以通过compact()
添加一行来摆脱调用:
var result = [];
_.each(a, function(ea) {
var entry = _.find(b, function(eb) {return ea.id == eb.id;});
if (entry) result.push(entry);
});
回答by Jacob
I'd like to share my generalsolution for those cases.
我想分享我对这些情况的一般解决方案。
I added a general function to underscore, using mixin, which performs a binary 'array' operation on two collections, according to a given Hash function:
我添加了一个通用函数来下划线,使用 mixin,它根据给定的 Hash 函数对两个集合执行二进制“数组”操作:
_.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];
});
}
});
Usage example:
用法示例:
_([{id:1,v:'q'},{id:2,v:'p'}]).collectionOperation([{id:3,v:'pq'}], 'id', _.union )
Note that 'id'may be replaced with a function.
请注意,'id'可以替换为一个函数。
I believe this solution is O(n+m).
我相信这个解决方案是 O(n+m)。
回答by Raja Jaganathan
In lodash 4.0.0. We can try like this
在 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');
Output:
输出:
[ {'id': 1, 'name': 'jake' } ];
[ {'id': 1, 'name': 'jake' } ];
回答by Joe
Technically, it does work on objects, but you need to be careful of reference equality.
从技术上讲,它确实适用于对象,但您需要注意引用相等性。
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]
回答by Umesh Patil
var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ];
var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ];
Working 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));
I have also tried code in jQuery specially after Pointy's suggestion. Compare has to be customizable as per the structure of JSON object.
在 Pointy 的建议之后,我还特别尝试了 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>
回答by giuseppe
If you wanna compare only objects:
如果您只想比较对象:
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' } }
回答by Derese Getachew
//nested array is in the format of [[],[],[]]
function objectArrayIntersection(nestedArrays){
let intersectingItems = [];
let uniqArr = _.uniq(_.flatten(nestedArrays)); //intersecting items removed
const countOfNestedArrays = nestedArrays.length;
for (let index = 0; index < uniqArr.length; index++) {
let uniqItem = uniqArr[index];
let foundCount = 0;
for(var j = 0;j<countOfNestedArrays;j++){
var i = _.indexOf(nestedArrays[j],uniqItem);
if(i != -1)
foundCount ++;
}
if(foundCount == countOfNestedArrays){
intersectingItems.push(uniqItem);
}
}
return intersectingItems;
}
I tried solving it this way.
我试过这样解决。
回答by Igor Timoshenko
var a = {a:'a1',b:'b1'},
b = {a:'a2',b:'b2',c:'c2'};
_.pick(a,_.intersection(_.keys(a),_.keys(b)));
// {a:'a1',b:'b1'}