Adotto un approccio leggermente più generico, sebbene simile nelle idee agli approcci di @Cerbrus e @Kasper Moerch . Creo una funzione che accetta un predicato per determinare se due oggetti sono uguali (qui ignoriamo la $$hashKey
proprietà, ma potrebbe essere qualsiasi cosa) e restituisco una funzione che calcola la differenza simmetrica di due elenchi in base a quel predicato:
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"}
Ha un piccolo vantaggio rispetto all'approccio di Cerebrus (così come l'approccio di Kasper Moerch) in quanto scappa presto; se trova una corrispondenza, non si preoccupa di controllare il resto della lista. Se avessi una curry
funzione a portata di mano, lo farei in modo leggermente diverso, ma funziona bene.
Spiegazione
Un commento richiedeva una spiegazione più dettagliata per i principianti. Ecco un tentativo.
Passiamo la seguente funzione a makeSymmDiffFunc
:
function(x, y) {
return x.value === y.value && x.display === y.display;
}
Questa funzione è il modo in cui decidiamo che due oggetti sono uguali. Come tutte le funzioni che restituiscono true
o false
, può essere chiamata "funzione predicato", ma questa è solo terminologia. Il punto principale è che makeSymmDiffFunc
è configurato con una funzione che accetta due oggetti e restituisce true
se li consideriamo uguali, false
se non lo facciamo.
Usando quello, makeSymmDiffFunc
(leggi "crea funzione differenza simmetrica") ci restituisce una nuova funzione:
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
Questa è la funzione che useremo effettivamente. Gli passiamo due liste e trova gli elementi nella prima non nella seconda, poi quelli nella seconda non nella prima e uniamo queste due liste.
Ripensandoci, però, avrei sicuramente potuto prendere spunto dal tuo codice e semplificare un po 'la funzione principale usando 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
usa il predicato e restituisce gli elementi del suo primo elenco non nel secondo. Questo è più semplice del mio primo passaggio con una contains
funzione separata .
Infine, la funzione principale è racchiusa in un'espressione di funzione richiamata immediatamente ( IIFE ) per mantenere la complement
funzione interna fuori dall'ambito globale.
Aggiornamento, pochi anni dopo
Ora che ES2015 è diventato abbastanza onnipresente, suggerirei la stessa tecnica, con molto meno 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"}