Eu adoto uma abordagem um pouco mais geral, embora semelhante em ideias às abordagens de @Cerbrus e @Kasper Moerch . Eu crio uma função que aceita um predicado para determinar se dois objetos são iguais (aqui nós ignoramos a $$hashKey
propriedade, mas pode ser qualquer coisa) e retorno uma função que calcula a diferença simétrica de duas listas com base nesse 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"}
Tem uma pequena vantagem sobre a abordagem de Cerebrus (assim como a abordagem de Kasper Moerch) por escapar mais cedo; se encontrar uma correspondência, não se preocupa em verificar o resto da lista. Se eu tivesse uma curry
função útil, faria isso de maneira um pouco diferente, mas funciona bem.
Explicação
Um comentário pedia uma explicação mais detalhada para iniciantes. Aqui está uma tentativa.
Passamos a seguinte função para makeSymmDiffFunc
:
function(x, y) {
return x.value === y.value && x.display === y.display;
}
Esta função é como decidimos que dois objetos são iguais. Como todas as funções que retornam true
ou false
, pode ser chamada de "função de predicado", mas isso é apenas terminologia. O ponto principal é que makeSymmDiffFunc
se configure com uma função que aceita dois objetos e retorna true
se os considerarmos iguais, false
se não o fizermos.
Usando isso, makeSymmDiffFunc
(leia "fazer função de diferença simétrica") retorna uma nova função:
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
Esta é a função que realmente usaremos. Passamos duas listas e ele encontra os elementos da primeira, não da segunda, então os da segunda, que não estão na primeira, e combina essas duas listas.
No entanto, olhando novamente, eu poderia definitivamente ter entendido seu código e simplificado a função principal um pouco 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 o predicado e retorna os elementos da primeira lista, não da segunda. Isso é mais simples do que minha primeira passagem com uma contains
função separada .
Finalmente, a função principal é envolvida em uma expressão de função imediatamente chamada ( IIFE ) para manter a complement
função interna fora do escopo global.
Atualização, alguns anos depois
Agora que o ES2015 se tornou bastante onipresente, eu sugeriria a mesma técnica, com muito menos clichê:
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"}