210

I have two result sets like this:

// Result 1
[
    { value: "0", display: "Jamsheer" },
    { value: "1", display: "Muhammed" },
    { value: "2", display: "Ravi" },
    { value: "3", display: "Ajmal" },
    { value: "4", display: "Ryan" }
]

// Result 2
[
    { value: "0", display: "Jamsheer" },
    { value: "1", display: "Muhammed" },
    { value: "2", display: "Ravi" },
    { value: "3", display: "Ajmal" },
]

The final result I need is the difference between these arrays – the final result should be like this:

[{ value: "4", display: "Ryan" }]

Is it possible to do something like this in JavaScript?

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
BKM
  • 6,949
  • 7
  • 30
  • 45

24 Answers24

225

Using only native JS, something like this will work:

const a = [{ value:"0", display:"Jamsheer" }, { value:"1", display:"Muhammed" }, { value:"2", display:"Ravi" }, { value:"3", display:"Ajmal" }, { value:"4", display:"Ryan" }];
const b = [{ value:"0", display:"Jamsheer", $$hashKey:"008" }, { value:"1", display:"Muhammed", $$hashKey:"009" }, { value:"2", display:"Ravi", $$hashKey:"00A" }, { value:"3", display:"Ajmal", $$hashKey:"00B" }];

// A comparer used to determine if two entries are equal.
const isSameUser = (a, b) => a.value === b.value && a.display === b.display;

// Get items that only occur in the left array,
// using the compareFunction to determine equality.
const onlyInLeft = (left, right, compareFunction) => 
  left.filter(leftValue =>
    !right.some(rightValue => 
      compareFunction(leftValue, rightValue)));

const onlyInA = onlyInLeft(a, b, isSameUser);
const onlyInB = onlyInLeft(b, a, isSameUser);

const result = [...onlyInA, ...onlyInB];

console.log(result);
Cerbrus
  • 70,800
  • 18
  • 132
  • 147
  • 2
    This works, and is maybe the best direct answer, but it would be nice to turn it into something that accepted a predicate and two lists and returned the symmetric difference of the two lists by applying the predicate appropriately. (Extra points if it were more efficient than having to run through all m * n comparisons twice!) – Scott Sauyet Feb 24 '14 at 12:55
  • @ScottSauyet: I'm not familiar with the term _"predicate"_ (Not a native English speaker). Is that the `return a.value ===...` in your answer? (Nice solution, by the way, +1) Aside from using `Array.prototype.some()`, I can't really find a more efficient / shorter way of doing this. – Cerbrus Feb 24 '14 at 14:08
  • 2
    @Cerbrus: Yes. A predicate is a function that returns a boolean (`true` or `false` value.) In this case, if we separate out the notion of testing for equality from the rest of the code by requiring the user to pass the equality check as a function, we can make a straightforward generic algorithm. – Scott Sauyet Feb 24 '14 at 14:29
  • 1
    @ScottSauyet: It's taken a while for me to find this answer again, but now it's quite a bit better :D – Cerbrus Jul 12 '17 at 14:45
  • ES6 const comparer = (otherArray) => (current) => otherArray.filter((other) => other.value == current.value && other.display == current.display).length == 0; – Shnigi Mar 05 '19 at 09:17
  • Can someone explain the above code, why do you have to take the length of the array? – Whymess Aug 13 '20 at 01:54
  • 1
    That comparer runs the inner function for every item in the current array. The `otherArray.filter` returns an array of items from `otherArray` that are the same as the current item. If there are any such items (`.length > 0`), the current item isn't unique between the two arrays, so the current item shouldn't be returned from the `comparer` @Whymess. – Cerbrus Aug 13 '20 at 05:33
  • 1
    I love this answer it's brilliant thank you – Amir Hassan Azimi Dec 01 '21 at 15:18
  • 1
    This answer works 100%. I even modified to my use case and works even better. Been looking for something like this for a while now. – Africanfruit Mar 25 '22 at 14:20
  • @Cerbrus What happens in the event that there is another array inside both, and you want to compare these internal arrays? if those internal arrays are different... – Jose Manuel Mar 27 '22 at 08:39
  • @JoseManuel then your compare function would have to be able to handle that… – Cerbrus Mar 27 '22 at 08:59
  • @Cerbrus when I add when comparing the arrays, it returns everything. As if I found everyone different. internal arrays also have their keys-value (value and display for example) – Jose Manuel Mar 27 '22 at 09:49
  • You can’t use `===` to compare those internal arrays. – Cerbrus Mar 27 '22 at 09:55
  • @Cerbrus https://jsfiddle.net/dwp2Lygs/1/ add an internal array (list). I try to get **Ryan** _(who changed his value)_ and **Jamsheer** _(whose internal array is different from the other, either because his array is larger or because his internal values changed)_ – Jose Manuel Mar 27 '22 at 16:53
  • @JoseManuel `a.list === b.list` you can't compare arrays like that. – Cerbrus Mar 27 '22 at 17:18
198

For those who like one-liner solutions in ES6, something like this:

const arrayOne = [ 
  { value: "4a55eff3-1e0d-4a81-9105-3ddd7521d642", display: "Jamsheer" },
  { value: "644838b3-604d-4899-8b78-09e4799f586f", display: "Muhammed" },
  { value: "b6ee537a-375c-45bd-b9d4-4dd84a75041d", display: "Ravi" },
  { value: "e97339e1-939d-47ab-974c-1b68c9cfb536", display: "Ajmal" },
  { value: "a63a6f77-c637-454e-abf2-dfb9b543af6c", display: "Ryan" },
];
          
const arrayTwo = [
  { value: "4a55eff3-1e0d-4a81-9105-3ddd7521d642", display: "Jamsheer"},
  { value: "644838b3-604d-4899-8b78-09e4799f586f", display: "Muhammed"},
  { value: "b6ee537a-375c-45bd-b9d4-4dd84a75041d", display: "Ravi"},
  { value: "e97339e1-939d-47ab-974c-1b68c9cfb536", display: "Ajmal"},
];

const results = arrayOne.filter(({ value: id1 }) => !arrayTwo.some(({ value: id2 }) => id2 === id1));

console.log(results);
atheane
  • 2,101
  • 1
  • 8
  • 7
  • 16
    Explain it please! – Bruno Brito Feb 18 '20 at 00:46
  • I like this solution. It creates a temp object with only a value property, so keep it small – deanwilliammills Sep 17 '20 at 12:13
  • Returned empty array even if there is a difference in the object, but the structure in itself is not different ```const arrayOne = [{foo: 'bar'}, {bar: 'foo'}]; const arrayTwo = [{foo: ''}, {bar: 'foo'}];``` – Harsh Phoujdar Oct 29 '21 at 09:48
  • 3
    doesnt work on all cases, returns unique objects from the first object only. – Sami Ullah Jan 27 '22 at 13:41
  • 3
    This doesn´t work if the different object is in the second array – sakramento Apr 30 '22 at 23:45
  • 1
    @sakramento yes, order matters here, as it does in lodash `_.difference` – Siddhartha Jul 04 '22 at 02:53
  • Am i correct in thinking that this only checks for items in 1 that arent in 2, but not the other way around? – Phill Healey Jul 06 '22 at 11:43
  • This works. But we have to maintain 2 `results`, just like this one [stackoverflow](https://stackoverflow.com/a/21988249/10603183). **edit: ** use `JSON.stringify(obj)` when comparing objects. – Zeeshan Jul 09 '22 at 03:25
  • This works absolutely fine in my use case... this approach works like magic. – taiseen Sep 13 '22 at 19:35
  • For use cases when you have to compare multiple values it works like this ```const diff= arr?.filter( ({ symbol: symbol_1, asset_class: asset_class_1 }) => !pending?.some( ({ symbol: symbol_2, asset_class: asset_class_2 }) => symbol_1 === symbol_2 && asset_class_1 === asset_class_2 ) ); ``` – Michael Sep 20 '22 at 08:29
102

You could use Array.prototype.filter() in combination with Array.prototype.some().

Here is an example (assuming your arrays are stored in the variables result1 and result2):

//Find values that are in result1 but not in result2
var uniqueResultOne = result1.filter(function(obj) {
    return !result2.some(function(obj2) {
        return obj.value == obj2.value;
    });
});

//Find values that are in result2 but not in result1
var uniqueResultTwo = result2.filter(function(obj) {
    return !result1.some(function(obj2) {
        return obj.value == obj2.value;
    });
});

//Combine the two arrays of unique entries
var result = uniqueResultOne.concat(uniqueResultTwo);
Andy
  • 61,948
  • 13
  • 68
  • 95
kaspermoerch
  • 16,127
  • 4
  • 44
  • 67
28
import differenceBy from 'lodash/differenceBy'

const myDifferences = differenceBy(Result1, Result2, 'value')

This will return the difference between two arrays of objects, using the key value to compare them. Note two things with the same value will not be returned, as the other keys are ignored.

This is a part of lodash.

Noah
  • 4,601
  • 9
  • 39
  • 52
  • The json object above is wrong. When try this way change = for : – Walter Zalazar Apr 26 '17 at 13:55
  • 1
    to install it, you need to write it lowercase: ```npm i lodash.differenceby```. The nice thing is that ```differenceBy(Result1, Result2, 'value')``` is different than ```differenceBy(Result2, Result1, 'value')``` so you can use one to see what has been deleted and the other to see what has been added. Very useful. – Raphael Pinel Sep 04 '21 at 18:33
17

I take a slightly more general-purpose approach, although similar in ideas to the approaches of both @Cerbrus and @Kasper Moerch. I create a function that accepts a predicate to determine if two objects are equal (here we ignore the $$hashKey property, but it could be anything) and return a function which calculates the symmetric difference of two lists based on that predicate:

a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"},  { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}]
b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}]

var makeSymmDiffFunc = (function() {
    var contains = function(pred, a, list) {
        var idx = -1, len = list.length;
        while (++idx < len) {if (pred(a, list[idx])) {return true;}}
        return false;
    };
    var complement = function(pred, a, b) {
        return a.filter(function(elem) {return !contains(pred, elem, b);});
    };
    return function(pred) {
        return function(a, b) {
            return complement(pred, a, b).concat(complement(pred, b, a));
        };
    };
}());

var myDiff = makeSymmDiffFunc(function(x, y) {
    return x.value === y.value && x.display === y.display;
});

var result = myDiff(a, b); //=>  {value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan"}

It has one minor advantage over Cerebrus's approach (as does Kasper Moerch's approach) in that it escapes early; if it finds a match, it doesn't bother checking the rest of the list. If I had a curry function handy, I would do this a little differently, but this works fine.

Explanation

A comment asked for a more detailed explanation for beginners. Here's an attempt.

We pass the following function to makeSymmDiffFunc:

function(x, y) {
    return x.value === y.value && x.display === y.display;
}

This function is how we decide that two objects are equal. Like all functions that return true or false, it can be called a "predicate function", but that's just terminology. The main point is that makeSymmDiffFunc is configured with a function that accepts two objects and returns true if we consider them equal, false if we don't.

Using that, makeSymmDiffFunc (read "make symmetric difference function") returns us a new function:

        return function(a, b) {
            return complement(pred, a, b).concat(complement(pred, b, a));
        };

This is the function we will actually use. We pass it two lists and it finds the elements in the first not in the second, then those in the second not in the first and combine these two lists.

Looking over it again, though, I could definitely have taken a cue from your code and simplified the main function quite a bit by using some:

var makeSymmDiffFunc = (function() {
    var complement = function(pred, a, b) {
        return a.filter(function(x) {
            return !b.some(function(y) {return pred(x, y);});
        });
    };
    return function(pred) {
        return function(a, b) {
            return complement(pred, a, b).concat(complement(pred, b, a));
        };
    };
}());

complement uses the predicate and returns the elements of its first list not in its second. This is simpler than my first pass with a separate contains function.

Finally, the main function is wrapped in an immediately invoked function expression (IIFE) to keep the internal complement function out of the global scope.


Update, a few years later

Now that ES2015 has become pretty well ubiquitous, I would suggest the same technique, with a lot less boilerplate:

const diffBy = (pred) => (a, b) => a.filter(x => !b.some(y => pred(x, y)))
const makeSymmDiffFunc = (pred) => (a, b) => diffBy(pred)(a, b).concat(diffBy(pred)(b, a))

const myDiff = makeSymmDiffFunc((x, y) => x.value === y.value && x.display === y.display)

const result = myDiff(a, b)
//=>  {value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan"}
Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
  • 3
    Could you add some more explanation to your code? I'm not sure a beginner in JavaScript would understand how the predicate-approach works. – kaspermoerch Feb 25 '14 at 15:44
  • 1
    @KasperMoerch: Added a longish explanation. I hope that helps. (It also made me recognize a serious clean-up that this code should have.) – Scott Sauyet Feb 25 '14 at 16:39
15

In addition, say two object array with different key value

// Array Object 1
const arrayObjOne = [
    { userId: "1", display: "Jamsheer" },
    { userId: "2", display: "Muhammed" },
    { userId: "3", display: "Ravi" },
    { userId: "4", display: "Ajmal" },
    { userId: "5", display: "Ryan" }
]

// Array Object 2
const arrayObjTwo =[
    { empId: "1", display: "Jamsheer", designation:"Jr. Officer" },
    { empId: "2", display: "Muhammed", designation:"Jr. Officer" },
    { empId: "3", display: "Ravi", designation:"Sr. Officer" },
    { empId: "4", display: "Ajmal", designation:"Ast. Manager" },
]

You can use filter in es5 or native js to substract two array object.

//Find data that are in arrayObjOne but not in arrayObjTwo
var uniqueResultArrayObjOne = arrayObjOne.filter(function(objOne) {
    return !arrayObjTwo.some(function(objTwo) {
        return objOne.userId == objTwo.empId;
    });
});

In ES6 you can use Arrow function with Object destructuring of ES6.

const ResultArrayObjOne = arrayObjOne.filter(({ userId: userId }) => !arrayObjTwo.some(({ empId: empId }) => empId === userId));

console.log(ResultArrayObjOne);
Majedur
  • 3,074
  • 1
  • 30
  • 43
  • 1
    You saved me brother! ES6 code snippets works better. Thanks! – Niyongabo Eric Jul 06 '21 at 23:31
  • Thanks for that one! I would have written it like that personally `arrayObjOne.filter(objectOne => !arrayObjTwo.some(objectTwo => objectOne.userId === objectTwo.empId))` but your approach is still valid, I myself feel like destructuring can be a tidy confusing in that case. – kissu Dec 05 '22 at 18:13
8

You can create an object with keys as the unique value corresponding for each object in array and then filter each array based on existence of the key in other's object. It reduces the complexity of the operation.

ES6

let a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"},  { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}];
let b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}];

let valuesA = a.reduce((a,{value}) => Object.assign(a, {[value]:value}), {});
let valuesB = b.reduce((a,{value}) => Object.assign(a, {[value]:value}), {});
let result = [...a.filter(({value}) => !valuesB[value]), ...b.filter(({value}) => !valuesA[value])];
console.log(result);

ES5

var a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"},  { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}];
var b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}];

var valuesA = a.reduce(function(a,c){a[c.value] = c.value; return a; }, {});
var valuesB = b.reduce(function(a,c){a[c.value] = c.value; return a; }, {});
var result = a.filter(function(c){ return !valuesB[c.value]}).concat(b.filter(function(c){ return !valuesA[c.value]}));
console.log(result);
Nikhil Aggarwal
  • 28,197
  • 4
  • 43
  • 59
7

I found this solution using filter and some.

resultFilter = (firstArray, secondArray) => {
  return firstArray.filter(firstArrayItem =>
    !secondArray.some(
      secondArrayItem => firstArrayItem._user === secondArrayItem._user
    )
  );
};
Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
Gorez Tony
  • 89
  • 1
  • 6
6

I think the @Cerbrus solution is spot on. I have implemented the same solution but extracted the repeated code into it's own function (DRY).

 function filterByDifference(array1, array2, compareField) {
  var onlyInA = differenceInFirstArray(array1, array2, compareField);
  var onlyInb = differenceInFirstArray(array2, array1, compareField);
  return onlyInA.concat(onlyInb);
}

function differenceInFirstArray(array1, array2, compareField) {
  return array1.filter(function (current) {
    return array2.filter(function (current_b) {
        return current_b[compareField] === current[compareField];
      }).length == 0;
  });
}
Michael
  • 93
  • 1
  • 4
5

you can do diff a on b and diff b on a, then merge both results

let a = [
    { value: "0", display: "Jamsheer" },
    { value: "1", display: "Muhammed" },
    { value: "2", display: "Ravi" },
    { value: "3", display: "Ajmal" },
    { value: "4", display: "Ryan" }
]

let b = [
    { value: "0", display: "Jamsheer" },
    { value: "1", display: "Muhammed" },
    { value: "2", display: "Ravi" },
    { value: "3", display: "Ajmal" }
]

// b diff a
let resultA = b.filter(elm => !a.map(elm => JSON.stringify(elm)).includes(JSON.stringify(elm)));

// a diff b
let resultB = a.filter(elm => !b.map(elm => JSON.stringify(elm)).includes(JSON.stringify(elm)));  

// show merge 
console.log([...resultA, ...resultB]);
lemospy
  • 371
  • 5
  • 8
4

let obj1 =[
                 { id: 1, submenu_name: 'login' },
                 { id: 2, submenu_name: 'Profile',}, 
                 { id: 3, submenu_name: 'password',  },  
                 { id: 4, submenu_name: 'reset',}
               ] ;
 let obj2 =[
                 { id: 2}, 
                 { id: 3 },
               ] ;
               
// Need Similar obj 
const result1 = obj1.filter(function(o1){
 return obj2.some(function(o2){
    return o1.id == o2.id;          // id is unnique both array object
  });
});
 console.log(result1);



// Need differnt obj 
 const result2 = obj1.filter(function(o1){
 return !obj2.some(function(o2){    //  for diffrent we use NOT (!) befor obj2 here
    return o1.id == o2.id;          // id is unnique both array object
  });
});
 console.log(result2);
Sonu P.
  • 85
  • 1
  • 5
2

JavaScript has Maps, that provide O(1) insertion and lookup time. Therefore this can be solved in O(n) (and not O(n²) as all the other answers do). For that, it is necessary to generate a unique primitive (string / number) key for each object. One could JSON.stringify, but that's quite error prone as the order of elements could influence equality:

 JSON.stringify({ a: 1, b: 2 }) !== JSON.stringify({ b: 2, a: 1 })

Therefore, I'd take a delimiter that does not appear in any of the values and compose a string manually:

const toHash = value => value.value + "@" + value.display;

Then a Map gets created. When an element exists already in the Map, it gets removed, otherwise it gets added. Therefore only the elements that are included odd times (meaning only once) remain. This will only work if the elements are unique in each array:

const entries = new Map();

for(const el of [...firstArray, ...secondArray]) {
  const key = toHash(el);
  if(entries.has(key)) {
    entries.delete(key);
  } else {
    entries.set(key, el);
  }
}

const result = [...entries.values()];

const firstArray = [
    { value: "0", display: "Jamsheer" },
    { value: "1", display: "Muhammed" },
    { value: "2", display: "Ravi" },
    { value: "3", display: "Ajmal" },
    { value: "4", display: "Ryan" }
]

const secondArray = [
    { value: "0", display: "Jamsheer" },
    { value: "1", display: "Muhammed" },
    { value: "2", display: "Ravi" },
    { value: "3", display: "Ajmal" },
];

const toHash = value => value.value + "@" + value.display;

const entries = new Map();

for(const el of [...firstArray, ...secondArray]) {
  const key = toHash(el);
  if(entries.has(key)) {
    entries.delete(key);
  } else {
    entries.set(key, el);
  }
}
  
const result = [...entries.values()];

console.log(result);
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
2

Most of the observed code does not examine the whole object and only compares the value of a particular method. This solution is the same, except that you can specify that method yourself.

Here is an example:

const arr1 = [
   {
      id: 1,
      name: "Tom",
      scores: {
         math: 80,
         science: 100
      }
   },
   {
      id: 2,
      name: "John",
      scores: {
         math: 50,
         science: 70
      }
   }
];
const arr2 = [
   {
      id: 1,
      name: "Tom",
      scores: {
         math: 80,
         science: 70
      }
   }
];

function getDifference(array1, array2, attr) {
  return array1.filter(object1 => {
    return !array2.some(object2 => {
      return eval("object1." + attr + " == object2." + attr);
    });
  });
}

// ️ [{id: 2, name: 'John'...
console.log(getDifference(arr1, arr2, "id"));

// ️ [{id: 2, name: 'John'...
console.log(getDifference(arr1, arr2, "scores.math"));

// ️ [{id: 1, name: 'Tom'...
console.log(getDifference(arr1, arr2, "scores.science"));
Nabi K.A.Z.
  • 9,887
  • 6
  • 59
  • 81
2

@atheane response : fork :

const newList = [ 
  { value: "4a55eff3-1e0d-4a81-9105-3ddd7521d642", display: "Jamsheer" },
  { value: "644838b3-604d-4899-8b78-09e4799f586f", display: "Muhammed" },
  { value: "b6ee537a-375c-45bd-b9d4-4dd84a75041d", display: "Ravi2" },
  { value: "a63a6f77-c637-454e-abf2-dfb9b543af6c", display: "Ryan" },
];
          
const oldList = [
  { value: "4a55eff3-1e0d-4a81-9105-3ddd7521d642", display: "Jamsheer"},
  { value: "644838b3-604d-4899-8b78-09e4799f586f", display: "Muhammed"},
  { value: "b6ee537a-375c-45bd-b9d4-4dd84a75041d", display: "Ravi"},
  { value: "e97339e1-939d-47ab-974c-1b68c9cfb536", display: "Ajmal"},
];

const resultsAdd = newList.filter(({ value: id1 }) => !oldList.some(({ value: id2 }) => id2 === id1));
const resultsRemove = oldList.filter(({ value: id1 }) => !newList.some(({ value: id2 }) => id2 === id1));
const resultsUpdate = newList.filter(({ value: id1, ...rest1 }) => oldList.some(({ value: id2, ...rest2 }) => id2 === id1 && JSON.stringify(rest1) !== JSON.stringify(rest2)));

console.log("added", resultsAdd);
console.log("removed", resultsRemove);
console.log("updated", resultsUpdate);
1

Most of answers here are rather complex, but isn't logic behind this quite simple?

  1. check which array is longer and provide it as first parameter (if length is equal, parameters order doesnt matter)
  2. Iterate over array1.
  3. For current iteration element of array1 check if it is present in array2
  4. If it is NOT present, than
  5. Push it to 'difference' array
const getArraysDifference = (longerArray, array2) => {
  const difference = [];

  longerArray.forEach(el1 => {      /*1*/
    el1IsPresentInArr2 = array2.some(el2 => el2.value === el1.value); /*2*/

    if (!el1IsPresentInArr2) { /*3*/
      difference.push(el1);    /*4*/
    }
  });

  return difference;
}

O(n^2) complexity.

azrahel
  • 1,143
  • 2
  • 13
  • 31
1

I prefer map object when it comes to big arrays.

// create tow arrays
array1 = Array.from({length: 400},() => ({value:Math.floor(Math.random() * 4000)}))
array2 = Array.from({length: 400},() => ({value:Math.floor(Math.random() * 4000)}))

// calc diff with some function
console.time('diff with some');
results = array2.filter(({ value: id1 }) => array1.some(({ value: id2 }) => id2 === id1));
console.log('diff results ',results.length)
console.timeEnd('diff with some');

// calc diff with map object
console.time('diff with map');
array1Map = {};
for(const item1 of array1){
    array1Map[item1.value] = true;
}
results = array2.filter(({ value: id2 }) => array1Map[id2]);
console.log('map results ',results.length)
console.timeEnd('diff with map');
yoni12ab
  • 21
  • 2
1

Having:

const array = [{id:3, name:'xx'} , {id:7, name:'yy'}, {id:9, name:'zz'}];
const array2 =[3,4,5];//These are a group of ids

I made a function that removes the objects from array that matches de ids within array2, like this:

export const aFilter = (array, array2) => {
   
   array2.forEach(element => {
      array = array.filter(item=> item.id !== element);
   });
   return array;
}

After calling the function we should have the array with no object wit id = 3

const rta = aFilter(array, array2);
//rta should be = [{id:7, name:'yy'}, {id:9, name:'zz'}];

It worked for me, and was pretty easy

0

I've made a generalized diff that compare 2 objects of any kind and can run a modification handler gist.github.com/bortunac "diff.js" an ex of using :

old_obj={a:1,b:2,c:[1,2]}
now_obj={a:2 , c:[1,3,5],d:55}

so property a is modified, b is deleted, c modified, d is added

var handler=function(type,pointer){
console.log(type,pointer,this.old.point(pointer)," | ",this.now.point(pointer)); 

}

now use like

df=new diff();
df.analize(now_obj,old_obj);
df.react(handler);

the console will show

mdf ["a"]  1 | 2 
mdf ["c", "1"]  2 | 3 
add ["c", "2"]  undefined | 5 
add ["d"]  undefined | 55 
del ["b"]  2 | undefined 
bortunac
  • 4,642
  • 1
  • 32
  • 21
0

Most generic and simple way:

findObject(listOfObjects, objectToSearch) {
    let found = false, matchingKeys = 0;
    for(let object of listOfObjects) {
        found = false;
        matchingKeys = 0;
        for(let key of Object.keys(object)) {
            if(object[key]==objectToSearch[key]) matchingKeys++;
        }
        if(matchingKeys==Object.keys(object).length) {
            found = true;
            break;
        }
    }
    return found;
}

get_removed_list_of_objects(old_array, new_array) {
    // console.log('old:',old_array);
    // console.log('new:',new_array);
    let foundList = [];
    for(let object of old_array) {
        if(!this.findObject(new_array, object)) foundList.push(object);
    }
    return foundList;
}

get_added_list_of_objects(old_array, new_array) {
    let foundList = [];
    for(let object of new_array) {
        if(!this.findObject(old_array, object)) foundList.push(object);
    }
    return foundList;
}
0

I came across this question while searching for a way to pick out the first item in one array that does not match any of the values in another array and managed to sort it out eventually with array.find() and array.filter() like this

var carList= ['mercedes', 'lamborghini', 'bmw', 'honda', 'chrysler'];
var declinedOptions = ['mercedes', 'lamborghini'];

const nextOption = carList.find(car=>{
    const duplicate = declinedOptions.filter(declined=> {
      return declined === car
    })
    console.log('duplicate:',duplicate) //should list out each declined option
    if(duplicate.length === 0){//if theres no duplicate, thats the nextOption
      return car
    }
})

console.log('nextOption:', nextOption);
//expected outputs
//duplicate: mercedes
//duplicate: lamborghini
//duplicate: []
//nextOption: bmw

if you need to keep fetching an updated list before cross-checking for the next best option this should work well enough :)

Bimpong
  • 11
  • 1
0

const compare = (array1, array2) => array1.filter(i => !array2.some(o => i.value === o.value))
0

Get the difference between two object arrays with keys and values in JS.

var arr_1 = [
  { value: '0', display: 'Jamsheer' },
  { value: '1', display: 'Muhammed' },
  { value: '2', display: 'Ravi' },
  { value: '3', display: 'Ajmal' },
  { value: '4', display: 'Ryan' },
];

var arr_2 = [
  { value: '0', display: 'Jamsheer' },
  { value: '1', display: 'Muhammed' },
  { value: '2', display: 'Ravi' },
  { value: '3', display: 'Ajmal' },
  { value: '4', display: 'Thomas' },
  { value: '5', display: 'David' },
];

/*
result = [
  { value: '4', display: 'Ryan' },
  { value: '4', display: 'Thomas' },
  { value: '5', display: 'David' },
];
*/

const result_1 = arr_1.filter(
  ({ value, display: obj_1 }) =>
    !arr_2.some(({ value, display: obj_2 }) => obj_1 === obj_2)
);

const result_2 = arr_2.filter(
  ({ value, display: obj_2 }) =>
    !arr_1.some(({ value, display: obj_1 }) => obj_1 === obj_2)
);

const result = result_1.concat(result_2);
console.log(result);
Vương Hữu Thiện
  • 1,460
  • 14
  • 21
-1

Most simple way could be use of filter and some together Please refer below link DifferenceInTwoArrayOfObjectInSimpleWay

Aniket
  • 310
  • 1
  • 4
  • 22
-6

If you are willing to use external libraries, You can use _.difference in underscore.js to achieve this. _.difference returns the values from array that are not present in the other arrays.

_.difference([1,2,3,4,5][1,4,10])

==>[2,3,5]
Mubashir Kp
  • 255
  • 1
  • 2
  • 7
  • 14
    This only works on arrays with primitive values. If the array contains a list of objects, like this question asks, it will not work as it tries to compare the references instead of the objects themselves, which will almost always mean that everything is different. – Ross Peoples Dec 07 '15 at 19:15
  • 1
    thanks Ross you saved me from a headache. I was about to report a bug to underscore. – Etienne Dec 30 '15 at 04:05