如何使用下划线的“交集”在物体上?

发布于 2024-12-23 12:16:13 字数 471 浏览 2 评论 0原文

_.intersection([], [])

只适用于原始类型,对吧?

它不适用于对象。我怎样才能让它与对象一起工作(也许通过检查“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': '杰克' } ];

_.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)?

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' } ];

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

暖心男生 2024-12-30 12:16:13

您可以基于下划线的函数创建另一个函数。您只需更改原始函数中的一行代码:

_.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); });
      });
    });
  };

在本例中,您现在将使用 underscore 的 isEqual() 方法,而不是 JavaScript 的相等比较器。我用你的例子尝试了一下,效果很好。以下是 underscore 文档中有关 isEqual 函数的摘录:

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

您可以在此处找到文档: http:// documentcloud.github.com/underscore/#isEqual

我将代码放在 jsFiddle 上,以便您可以测试并确认它:http://jsfiddle.net/luisperezphd/jrJxT/

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(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

I put up the code on jsFiddle so you can test and confirm it: http://jsfiddle.net/luisperezphd/jrJxT/

清晰传感 2024-12-30 12:16:13

这是一种灵活且性能更好的替代算法。其中一项改进是您可以指定自己的比较函数,因此在您的情况下,如果 id 是唯一标识符,您可以只比较 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 上找到它: http://jsfiddle.net/luisperezphd/43vksdn6/

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.

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:

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

You can find it on jsFiddle here: http://jsfiddle.net/luisperezphd/43vksdn6/

浊酒尽余欢 2024-12-30 12:16:13

下划线中的数组方法非常强大,您应该只需要几行即可完成您想要做的事情:

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

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:

var result = [];
_.each(a, function(ea) {
    var entry = _.find(b, function(eb) {return ea.id == eb.id;});
    if (entry) result.push(entry);
});
满栀 2024-12-30 12:16:13

我想分享我针对这些情况的通用解决方案。

我使用 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' 可以替换为功能。

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

I'd like to share my general solution 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({
    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.

I believe this solution is O(n+m).

小女人ら 2024-12-30 12:16:13

在洛达什 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' } ];

In lodash 4.0.0. We can try like this

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' } ];

绿光 2024-12-30 12:16:13

从技术上讲,它确实适用于对象,但您需要注意引用相等性。

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]

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]
屋檐 2024-12-30 12:16:13
var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ];
var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ];

工作功能:

 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的建议之后,我还专门尝试了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>
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.

<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>
撧情箌佬 2024-12-30 12:16:13

如果您只想比较对象:

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

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' } }
幸福还没到 2024-12-30 12:16:13
//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;
}

我尝试用这种方法解决它。

//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.

过去的过去 2024-12-30 12:16:13
var a = {a:'a1',b:'b1'},
    b = {a:'a2',b:'b2',c:'c2'};

_.pick(a,_.intersection(_.keys(a),_.keys(b)));

// {a:'a1',b:'b1'}
var a = {a:'a1',b:'b1'},
    b = {a:'a2',b:'b2',c:'c2'};

_.pick(a,_.intersection(_.keys(a),_.keys(b)));

// {a:'a1',b:'b1'}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文