4

I need something like lodash.intersectionWith but I also need duplicated values in result array.

Example:

var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
_.intersectionWith(objects, others, _.isEqual);

Expected Result:

[{ 'x': 1, 'y': 2 },{ 'x': 1, 'y': 2 }]

Thanks in advance!

2
  • It's not exactly clear why you expect there to be 2 copies of that object and not 3. Commented May 25, 2016 at 10:22
  • Because array #1 has 2 values matching array #2 I'd guess Commented May 25, 2016 at 10:23

3 Answers 3

3

You can find the intersection by filtering out items from the first array that don't match items in the second. Any duplicates in the first array will be kept.

var intersectwith = function(f,xs,ys){
    return xs.filter(function(x){
        return ys.some(function(y){
            return f(x,y);
        });
    });
};

var equals = function(x,y){
    return x === y;
};
console.log(intersectwith(equals, [1,2,3], [1,1,2,2,4]));
console.log(intersectwith(equals, [1,1,2,2,4], [1,2,3]));

Or, more readably, using ES6:

const intersectwith = (f,xs,ys) => xs.filter(x => ys.some(y => f(x,y)));
const equals = (x,y) => x === y;

console.log(intersectwith(equals, [1,2,3], [1,1,2,2,4]));
console.log(intersectwith(equals, [1,1,2,2,4], [1,2,3]));

Substitute _.isEqual for equals for comparing objects: jsfiddle.

Useful documentation:
Array.prototype.filter
Array.prototype.some

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

2 Comments

You can use a different comparison function, e.g. _.isEqual. I wanted to show it working in the code snippet.
Edited to add jsfiddle showing it in action with objects.
3

You can make use of differenceWith() to get the difference between the source object and the symmetric difference of the source object and the others object using xorWith().

var result = _.differenceWith(
  objects, 
  _.xorWith(objects, others, _.isEqual), 
  _.isEqual
);

var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];


var intersection = _.intersectionWith(objects, others, _.isEqual);

var result = _.differenceWith(
  objects, 
  _.xorWith(objects, others, _.isEqual), 
  _.isEqual
);

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.js"></script>

6 Comments

I like this approach, but here is one problem, my actual arrays have different object types 'objects are Jquery' and 'others are javascript object'. The problem is that xorWith()'s comparator function at some point switches arguments (have no idea why).
@Mikhail please check my update, I changed difference() to differenceWith().
intersectionWith() works fine. I made a test you can check it out.
I can see that in your test, the source object does only contain the x and y property. You should have added such statement. And your test definitely failed. If you log the intersection result it would return an empty array.
I update demo. But any way it is just to see the difference between Xor and Intersection comparator functions.
|
0

Use reduce to validate each object in the first array, then check if that object exists in the second array. If it exists, reduce will push that object into its array.

The reduce function will return that new array automagically.

var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];

var res = objects.reduce(
  function(arr, obj){
    if(containsObject(obj, others))
      arr.push(obj);
    return arr;
  }, 
  []
);


function containsObject(obj, list) {
    var x;
    var ret = false;
  
    list.forEach(function(s){
      ret = JSON.stringify(s) == JSON.stringify(obj);
    });

    return ret;
}

console.log(res);

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.