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

use*_*495 42 javascript underscore.js

_.intersection([], [])
Run Code Online (Sandbox Code Playgroud)

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

它不适用于对象.如何使它与对象一起工作(可能通过检查"Id"字段)?

var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ]
var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ]
Run Code Online (Sandbox Code Playgroud)

在此示例中,结果应为:

_.intersection(a, b);
Run Code Online (Sandbox Code Playgroud)

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

Lui*_*rez 25

这是一种应该灵活且性能更好的替代算法.其中一个改进是您可以指定自己的比较功能,因此在您的情况下,如果它是唯一标识符,您可以只比较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;
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

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;
});
Run Code Online (Sandbox Code Playgroud)

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

var result = intersectionObjects(a, b, c);
Run Code Online (Sandbox Code Playgroud)

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


Lui*_*rez 24

您可以根据下划线的功能创建另一个功能.您只需要从原始函数更改一行代码:

_.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); });
      });
    });
  };
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您现在使用下划线的isEqual()方法而不是JavaScript的相等比较器.我用你的例子尝试了它并且它有效.以下是有关isEqual函数的下划线文档的摘录:

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

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

我把代码放在jsFiddle上,这样你就可以测试并确认它:http://jsfiddle.net/luisperezphd/jrJxT/

  • 这是3个循环所以基本上O(n ^ 3)肯定你可以做得更好.(尝试O(nlogn) (4认同)

Jul*_* D. 5

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

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();
Run Code Online (Sandbox Code Playgroud)

如果你有大型数组,你可以compact()通过一个额外的行来摆脱这个调用:

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