Adopto un enfoque un poco más de propósito general, aunque similar en ideas a los enfoques de @Cerbrus y @Kasper Moerch . Creo una función que acepta un predicado para determinar si dos objetos son iguales (aquí ignoramos la $$hashKey
propiedad, pero podría ser cualquier cosa) y devuelvo una función que calcula la diferencia simétrica de dos listas basadas en ese predicado:
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"}
Tiene una pequeña ventaja sobre el enfoque de Cerebrus (al igual que el enfoque de Kasper Moerch) en que se escapa temprano; si encuentra una coincidencia, no se molesta en comprobar el resto de la lista. Si tuviera una curry
función a mano, haría esto de manera un poco diferente, pero funciona bien.
Explicación
Un comentario pidió una explicación más detallada para principiantes. He aquí un intento.
Pasamos la siguiente función a makeSymmDiffFunc
:
function(x, y) {
return x.value === y.value && x.display === y.display;
}
Esta función es la forma en que decidimos que dos objetos son iguales. Como todas las funciones que devuelven true
o false
, se puede llamar una "función de predicado", pero eso es solo terminología. El punto principal es que makeSymmDiffFunc
está configurado con una función que acepta dos objetos y devuelve true
si los consideramos iguales, false
si no.
Usando eso, makeSymmDiffFunc
(lea "hacer una función de diferencia simétrica") nos devuelve una nueva función:
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
Esta es la función que realmente usaremos. Le pasamos dos listas y encuentra los elementos en la primera no en la segunda, luego los de la segunda no en la primera y combina estas dos listas.
Sin embargo, volviendo a mirarlo, definitivamente podría haber tomado una pista de su código y simplificar un poco la función principal 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 el predicado y devuelve los elementos de su primera lista, no de la segunda. Esto es más simple que mi primer paso con una contains
función separada .
Finalmente, la función principal está envuelta en una expresión de función invocada inmediatamente ( IIFE ) para mantener la complement
función interna fuera del alcance global.
Actualización, unos años después
Ahora que ES2015 se ha vuelto bastante ubicuo, sugeriría la misma técnica, con mucho menos repetición:
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"}