Comparing two arrays of objects, and exclude the elements who match values into new array in JS

157,879

Solution 1

Just using the Array iteration methods built into JS is fine for this:

var result1 = [
    {id:1, name:'Sandra', type:'user', username:'sandra'},
    {id:2, name:'John', type:'admin', username:'johnny2'},
    {id:3, name:'Peter', type:'user', username:'pete'},
    {id:4, name:'Bobby', type:'user', username:'be_bob'}
];

var result2 = [
    {id:2, name:'John', email:'[email protected]'},
    {id:4, name:'Bobby', email:'[email protected]'}
];

var props = ['id', 'name'];

var result = result1.filter(function(o1){
    // filter out (!) items in result2
    return !result2.some(function(o2){
        return o1.id === o2.id;          // assumes unique id
    });
}).map(function(o){
    // use reduce to make objects with only the required properties
    // and map to apply this to the filtered array as a whole
    return props.reduce(function(newo, name){
        newo[name] = o[name];
        return newo;
    }, {});
});

document.body.innerHTML = '<pre>' + JSON.stringify(result, null, 4) +
        '</pre>';

If you are doing this a lot, then by all means look at external libraries to help you out, but it's worth learning the basics first, and the basics will serve you well here.

Solution 2

well, this using lodash or vanilla javascript it depends on the situation.

but for just return the array that contains the differences can be achieved by the following, offcourse it was taken from @1983

var result = result1.filter(function (o1) {
    return !result2.some(function (o2) {
        return o1.id === o2.id; // return the ones with equal id
   });
});
// if you want to be more clever...
let result = result1.filter(o1 => !result2.some(o2 => o1.id === o2.id));

Solution 3

The same result can be achieved using Lodash.

var result1 = [
    {id:1, name:'Sandra', type:'user', username:'sandra'},
    {id:2, name:'John', type:'admin', username:'johnny2'},
    {id:3, name:'Peter', type:'user', username:'pete'},
    {id:4, name:'Bobby', type:'user', username:'be_bob'}
];

var result2 = [
    {id:2, name:'John', email:'[email protected]'},
    {id:4, name:'Bobby', email:'[email protected]'}
];

var result3 = _(result1) 
        .differenceBy(result2, 'id', 'name')
        .map(_.partial(_.pick, _, 'id', 'name'))
        .value();

console.log(result3);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>

You can get the desired result applying a difference between both arrays using the properties "id" and "name" as a way to "link" elements between them. If any of those properties are different, the elements are considered different (improbably in your case because id seems to be unique).

Lastly, you have to map the result in order to "omit" the undesired properties of the object.

Hope it helps.

Solution 4

I have searched a lot for a solution in which I can compare two array of objects with different attribute names (something like a left outer join). I came up with this solution. Here I used Lodash. I hope this will help you.

var Obj1 = [
    {id:1, name:'Sandra'},
    {id:2, name:'John'},   
];

var Obj2 = [
    {_id:2, name:'John'},
    {_id:4, name:'Bobby'}
];

var Obj3 = lodash.differenceWith(Obj1, Obj2, function (o1, o2) {
    return o1['id'] === o2['_id']
});

console.log(Obj3);
//  {id:1, name:'Sandra'}

Solution 5

Here is another solution using Lodash:

var _ = require('lodash');

var result1 = [
    {id:1, name:'Sandra', type:'user', username:'sandra'},
    {id:2, name:'John', type:'admin', username:'johnny2'},
    {id:3, name:'Peter', type:'user', username:'pete'},
    {id:4, name:'Bobby', type:'user', username:'be_bob'}
];

var result2 = [
    {id:2, name:'John', email:'[email protected]'},
    {id:4, name:'Bobby', email:'[email protected]'}
];

// filter all those that do not match
var result = types1.filter(function(o1){
    // if match found return false
    return _.findIndex(types2, {'id': o1.id, 'name': o1.name}) !== -1 ? false : true;
});

console.log(result);
Share:
157,879
Leo
Author by

Leo

Updated on July 08, 2022

Comments

  • Leo
    Leo almost 2 years

    here is my use case in JavaScript:

    I have two arrays of objects which have properties that match (id & name).

    var result1 = [
        {id:1, name:'Sandra', type:'user', username:'sandra'},
        {id:2, name:'John', type:'admin', username:'johnny2'},
        {id:3, name:'Peter', type:'user', username:'pete'},
        {id:4, name:'Bobby', type:'user', username:'be_bob'}
    ];
    
    var result2 = [
        {id:2, name:'John', email:'[email protected]'},
        {id:4, name:'Bobby', email:'[email protected]'}
    ];
    
    var props = ['id', 'name'];
    

    My goal is to have another array of objects containing only the elements which did not match. Like this:

    var result = [
        {id:1, name:'Sandra'},
        {id:3, name:'Peter'}
    ];
    

    I know that there is a way of doing this by going from result1 compare each object with the objects of result2, then compare their keys, and if did'n match, put the values in another object then push it in new array, but I wonder is there any more elegant way, like using lo-dash or underscore or something similar.

    Thank you!

    • Cerbrus
      Cerbrus over 8 years
      Sharing your research helps everyone. Tell us what you've tried and why it didn't meet your needs. This demonstrates that you've taken the time to try to help yourself, it saves us from reiterating obvious answers, and most of all it helps you get a more specific and relevant answer! Also see how to ask
    • hindmost
      hindmost over 8 years
      Explore it yourself: 1, 2.
    • Matthew Carpenter
      Matthew Carpenter over 8 years
  • Tibin Paul
    Tibin Paul over 6 years
    Simple and neat answer!
  • Jose the hose
    Jose the hose about 6 years
    The last line is my favourite line in this whole page!
  • Siddhartha
    Siddhartha almost 6 years
    isArrayEqual(a1,a2); function isArrayEquals(){}
  • Harrison Cramer
    Harrison Cramer about 5 years
    This should be the top answer. Single, clean line with no libraries required.
  • Art
    Art almost 5 years
    this answer does not work! it returns common elements rather than uniques.
  • Sunny Hebbar
    Sunny Hebbar almost 4 years
    To get unique elements instead of the common ones, change the last line to let result = result1.filter(o1 => !result2.some(o2 => o1.id === o2.id)); to return the opposite value
  • Nishanth Subramanya
    Nishanth Subramanya almost 3 years
    clean answer but it has n^2 complexity
  • Ashish Kamble
    Ashish Kamble over 2 years
    I wrote the last line, and forgot today why i wrote it, end up reading why i did that on that day, hahha
  • kolexinfos
    kolexinfos over 2 years
    Complexity is n^2