0

Problem: I want to get inetrsection of array of objects.

var a = [{id: 1, name: 'jake'}];
var b = [{id: 1, name: 'jake'}, {id: 4,name: 'jenny'}];
var c = [{id: 1,name: 'jake'}, {id: 4,name: 'jenny'}, {id: 9,name: 'nick'}];
intersect (a,b,c);// Find Intersection based on id key
// answer would be [{id: 1, name: 'jake'}]

I found this very help answer here How to use underscore's "intersection" on objects?

BUT This solution uses underscore.js while i am using jquery.

I cant seems to know what _.any is doing. Any Help will be appreciated.

Here is complete Code

CODE: http://jsfiddle.net/luisperezphd/43vksdn6/

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;
});
Community
  • 1
  • 1
django
  • 2,809
  • 5
  • 47
  • 80

2 Answers2

1

This solution counts the same given objects with the same property and returns them if they in both of the arrays intersection().

function intersection(a, b, key) {
    function count(a) {
        o[a[key]] = o[a[key]] || { value: a, count: 0 };
        o[a[key]].count++;
    }
    var o = {}, r = [];
    a.forEach(count);
    b.forEach(count);
    Object.keys(o).forEach(function (k) {
        o[k].count === 2 && r.push(o[k].value);
    });
    return r;
}

function intersect(a, b, c, key) {
    return intersection(intersection(a, b, key), c, key);
}

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

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

This works now with a callback in this style.

function (v) { 
    return v.id;
}

It needs to returns a stringable value and can contain other value and combinations like this example which intersects with name and age (if existing in the data):

function (v) { 
    return v.name + '|' + v.age;
}

function intersection(a, b, cb) {
    function count(a) {
        o[cb(a)] = o[cb(a)] || { value: a, count: 0 };
        o[cb(a)].count++;
    }
    var o = {}, r = [];
    a.forEach(count);
    b.forEach(count);
    Object.keys(o).forEach(function (k) {
        o[k].count === 2 && r.push(o[k].value);
    });
    return r;
}

function intersect(a, b, c, key) {
    return intersection(intersection(a, b, key), c, key);
}

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

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • this is awesome. Can you please post a varinat where i can use a function instead of key so i can make custom logic – django Feb 18 '16 at 13:31
  • 1
    @django, please add some examples how the callback should look like. my answeris based on a specific key and it uses a linear approach for the solution. the other solution here presentet have the complexity of O(n*m), whereas my has O(n+m). – Nina Scholz Feb 18 '16 at 13:42
  • plz check my answer above. It uses callback. http://stackoverflow.com/a/35482678/2139859 – django Feb 18 '16 at 13:51
  • http://jsperf.com/intersection-of-array-of-objects I created performance test here and mine seems to be faster. But any improvement will be much appreciated – django Feb 18 '16 at 13:52
0

Here is my answer: Benefits are

  1. it gives me freedom to intersect as many objects as i want

  2. I can use Compare function where i can use equality or any logic I want

CODE:

var a = [ { id: 1, name: 'jake' } , { id: 4, name: 'jenny'}, { id: 9, name: 'nick'} ];
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 intersectionObjects = function() {
  var results = arguments[0];
  var lastArgument = arguments[arguments.length - 1];
  var arrayCount = arguments.length;
  var areEqualFunction;
  //Internal function
  var _intersection_of_2_Objects = function(array1, array2, areEqualFunction) {
    var result = []
    $.each(array1, function(indexArray1, valueArray1) {
      $.each(array2, function(indexArray2, valueArray2) {
        if (areEqualFunction(valueArray1, valueArray2)) {
          result.push(valueArray2)
        }
      });
    });
    return result;
  };
  //
  if (typeof lastArgument === "function") {
    areEqualFunction = lastArgument;
    arrayCount--;
  }
  for (var i = 1; i < arrayCount; i++) {
    var array = arguments[i];
    results = _intersection_of_2_Objects(results, array, areEqualFunction);
    if (results.length === 0) {
      break;
    }
  }
  return results;
};

Call it like :

var _intersect = intersectionObjects(b, c, a, function(valueArray1, valueArray2) {
  return (valueArray1.name == valueArray2.name);
});
console.log(_intersect);
django
  • 2,809
  • 5
  • 47
  • 80