I have two arrays list1 and list2 which have objects with some properties; userId is the Id or unique property:
list1 = [     { userId: 1234, userName: 'XYZ'  },      { userId: 1235, userName: 'ABC'  },      { userId: 1236, userName: 'IJKL' },     { userId: 1237, userName: 'WXYZ' },      { userId: 1238, userName: 'LMNO' } ]  list2 = [     { userId: 1235, userName: 'ABC'  },       { userId: 1236, userName: 'IJKL' },     { userId: 1252, userName: 'AAAA' } ]   I'm looking for an easy way to execute the following three operations:
list1 operation list2 should return the intersection of elements:
[     { userId: 1235, userName: 'ABC'  },     { userId: 1236, userName: 'IJKL' } ]  list1 operation list2 should return the list of all elements from list1 which don't occur in list2:
[     { userId: 1234, userName: 'XYZ'  },     { userId: 1237, userName: 'WXYZ' },      { userId: 1238, userName: 'LMNO' } ]  list2 operation list1 should return the list of elements from list2 which don't occur in list1:
[     { userId: 1252, userName: 'AAAA' } ]  The intersection of two arrays is a list of distinct numbers which are present in both the arrays. The numbers in the intersection can be in any order.
You could define three functions inBoth, inFirstOnly, and inSecondOnly which all take two lists as arguments, and return a list as can be understood from the function name. The main logic could be put in a common function operation that all three rely on.
Here are a few implementations for that operation to choose from, for which you can find a snippet further down:
for loopsfilter and some array methodsSet for loops// Generic helper function that can be used for the three operations:         function operation(list1, list2, isUnion) {     var result = [];          for (var i = 0; i < list1.length; i++) {         var item1 = list1[i],             found = false;         for (var j = 0; j < list2.length && !found; j++) {             found = item1.userId === list2[j].userId;         }         if (found === !!isUnion) { // isUnion is coerced to boolean             result.push(item1);         }     }     return result; }  // Following functions are to be used: function inBoth(list1, list2) {     return operation(list1, list2, true); }  function inFirstOnly(list1, list2) {     return operation(list1, list2); }  function inSecondOnly(list1, list2) {     return inFirstOnly(list2, list1); }  // Sample data var list1 = [     { userId: 1234, userName: 'XYZ'  },      { userId: 1235, userName: 'ABC'  },      { userId: 1236, userName: 'IJKL' },     { userId: 1237, userName: 'WXYZ' },      { userId: 1238, userName: 'LMNO' } ]; var list2 = [     { userId: 1235, userName: 'ABC'  },       { userId: 1236, userName: 'IJKL' },     { userId: 1252, userName: 'AAAA' } ];    console.log('inBoth:', inBoth(list1, list2));  console.log('inFirstOnly:', inFirstOnly(list1, list2));  console.log('inSecondOnly:', inSecondOnly(list1, list2));   filter and some array methodsThis uses some ES5 and ES6 features:
// Generic helper function that can be used for the three operations:         const operation = (list1, list2, isUnion = false) =>     list1.filter( a => isUnion === list2.some( b => a.userId === b.userId ) );  // Following functions are to be used: const inBoth = (list1, list2) => operation(list1, list2, true),       inFirstOnly = operation,       inSecondOnly = (list1, list2) => inFirstOnly(list2, list1);  // Sample data const list1 = [     { userId: 1234, userName: 'XYZ'  },      { userId: 1235, userName: 'ABC'  },      { userId: 1236, userName: 'IJKL' },     { userId: 1237, userName: 'WXYZ' },      { userId: 1238, userName: 'LMNO' } ]; const list2 = [     { userId: 1235, userName: 'ABC'  },       { userId: 1236, userName: 'IJKL' },     { userId: 1252, userName: 'AAAA' } ];    console.log('inBoth:', inBoth(list1, list2));  console.log('inFirstOnly:', inFirstOnly(list1, list2));  console.log('inSecondOnly:', inSecondOnly(list1, list2));  The above solutions have a O(n²) time complexity because of the nested loop -- some represents a loop as well. So for large arrays you'd better create a (temporary) hash on user-id. This can be done on-the-fly by providing a Set (ES6) as argument to a function that will generate the filter callback function. That function can then perform the look-up in constant time with has:
// Generic helper function that can be used for the three operations:         const operation = (list1, list2, isUnion = false) =>     list1.filter(         (set => a => isUnion === set.has(a.userId))(new Set(list2.map(b => b.userId)))     );  // Following functions are to be used: const inBoth = (list1, list2) => operation(list1, list2, true),       inFirstOnly = operation,       inSecondOnly = (list1, list2) => inFirstOnly(list2, list1);  // Sample data const list1 = [     { userId: 1234, userName: 'XYZ'  },      { userId: 1235, userName: 'ABC'  },      { userId: 1236, userName: 'IJKL' },     { userId: 1237, userName: 'WXYZ' },      { userId: 1238, userName: 'LMNO' } ]; const list2 = [     { userId: 1235, userName: 'ABC'  },       { userId: 1236, userName: 'IJKL' },     { userId: 1252, userName: 'AAAA' } ];    console.log('inBoth:', inBoth(list1, list2));  console.log('inFirstOnly:', inFirstOnly(list1, list2));  console.log('inSecondOnly:', inSecondOnly(list1, list2));  short answer:
list1.filter(a => list2.some(b => a.userId === b.userId));   list1.filter(a => !list2.some(b => a.userId === b.userId));   list2.filter(a => !list1.some(b => a.userId === b.userId));     longer answer:
 The code above will check objects by userId value,
 if you need complex compare rules, you can define custom comparator:
comparator = function (a, b) {     return a.userId === b.userId && a.userName === b.userName };   list1.filter(a => list2.some(b => comparator(a, b))); list1.filter(a => !list2.some(b => comparator(a, b))); list2.filter(a => !list1.some(b => comparator(a, b)));   Also there is a way to compare objects by references
WARNING! two objects with same values will be considered different:
o1 = {"userId":1}; o2 = {"userId":2}; o1_copy = {"userId":1}; o1_ref = o1; [o1].filter(a => [o2].includes(a)).length; // 0 [o1].filter(a => [o1_copy].includes(a)).length; // 0 [o1].filter(a => [o1_ref].includes(a)).length; // 1 
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With