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;
});
3
  • No, you want it in plain js, surely not in jQuery... Commented Feb 18, 2016 at 12:42
  • Yes plain JS solution would be fine as well or alternate to _.any in jquery if exists Commented Feb 18, 2016 at 12:44
  • jQuery and underscore.js are complimentary, not mutually exclusive. I recommend using the answer in the linked question. Commented Feb 18, 2016 at 14:28

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

4 Comments

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, 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).
plz check my answer above. It uses callback. stackoverflow.com/a/35482678/2139859
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
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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.