Differenza e intersezione di due array contenenti oggetti

Ho due array list1 e list2 che hanno oggetti con alcune proprietà; userId è l’Id o la proprietà unica:

 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' } ] 

Sto cercando un modo semplice per eseguire le seguenti tre operazioni:

  1. list1 operation list2 dovrebbe restituire l’intersezione di elementi:

     [ { userId: 1235, userName: 'ABC' }, { userId: 1236, userName: 'IJKL' } ] 
  2. list1 operation list2 dovrebbe restituire l’elenco di tutti gli elementi da list1 che non si verificano in list2 :

     [ { userId: 1234, userName: 'XYZ' }, { userId: 1237, userName: 'WXYZ' }, { userId: 1238, userName: 'LMNO' } ] 
  3. list2 operation list1 dovrebbe restituire la lista di elementi da list2 che non si verificano in list1 :

     [ { userId: 1252, userName: 'AAAA' } ] 

È ansible definire tre funzioni in inBoth , inFirstOnly e inSecondOnly che prendono tutti due elenchi come argomenti e restituiscono un elenco che può essere compreso dal nome della funzione. La logica principale potrebbe essere inserita in un’operazione di funzione comune su cui tutti e tre si affidano.

Ecco alcune implementazioni per l’ operation da cui scegliere, per le quali è ansible trovare uno snippet più in basso:

  • Semplice vecchio JavaScript for loop
  • Le funzioni freccia utilizzano il filter e some metodi di array
  • Ricerca ottimizzata con un Set

Plain old 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)); 

Usa il metodo _.isEqual di _.isEqual . In particolare:

 list1.reduce(function(prev, curr){ !list2.some(function(obj){ return _.isEqual(obj, curr) }) ? prev.push(curr): false; return prev }, []); 

Sopra ti dà l’equivalente di A given !B (in termini SQL, A LEFT OUTER JOIN B ). Puoi spostare il codice attorno al codice per ottenere quello che vuoi!

 function intersect(first, second) { return intersectInternal(first, second, function(e){ return e }); } function unintersect(first, second){ return intersectInternal(first, second, function(e){ return !e }); } function intersectInternal(first, second, filter) { var map = {}; first.forEach(function(user) { map[user.userId] = user; }); return second.filter(function(user){ return filter(map[user.userId]); }) } 

Questa è la soluzione che ha funzionato per me.

  var intersect = function (arr1, arr2) { var intersect = []; _.each(arr1, function (a) { _.each(arr2, function (b) { if (compare(a, b)) intersect.push(a); }); }); return intersect; }; var unintersect = function (arr1, arr2) { var unintersect = []; _.each(arr1, function (a) { var found = false; _.each(arr2, function (b) { if (compare(a, b)) { found = true; } }); if (!found) { unintersect.push(a); } }); return unintersect; }; function compare(a, b) { if (a.userId === b.userId) return true; else return false; } 

Ecco una soluzione di programmazione funzionale con underscore / lodash per rispondere alla tua prima domanda (intersezione).

 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'} ]; _.reduce(list1, function (memo, item) { var same = _.findWhere(list2, item); if (same && _.keys(same).length === _.keys(item).length) { memo.push(item); } return memo }, []); 

Ti lascerò migliorare per rispondere alle altre domande 😉