Przyjmuję nieco bardziej ogólne podejście, chociaż pomysły są podobne do podejść @Cerbrus i @Kasper Moerch . Tworzę funkcję, która przyjmuje predykat, aby określić, czy dwa obiekty są równe (tutaj ignorujemy tę $$hashKeywłaściwość, ale może to być cokolwiek) i zwracam funkcję, która oblicza symetryczną różnicę dwóch list na podstawie tego predykatu:
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"}
Ma jedną niewielką przewagę nad podejściem Cerebrusa (podobnie jak podejście Kaspera Moercha), ponieważ ucieka wcześnie; jeśli znajdzie dopasowanie, nie przejmuje się sprawdzaniem reszty listy. Gdybym miał pod curryręką funkcję, zrobiłbym to trochę inaczej, ale to działa dobrze.
Wyjaśnienie
W komentarzu prosiliśmy o bardziej szczegółowe wyjaśnienie dla początkujących. Oto próba.
Przekazujemy następującą funkcję do makeSymmDiffFunc:
function(x, y) {
return x.value === y.value && x.display === y.display;
}
Ta funkcja pozwala stwierdzić, że dwa obiekty są równe. Podobnie jak wszystkie funkcje, które zwracają wartość truelub false, można ją nazwać „funkcją predykatu”, ale to tylko terminologia. Najważniejsze jest to, że makeSymmDiffFuncjest skonfigurowana z funkcją, która przyjmuje dwa obiekty i zwraca, truejeśli uznamy je za równe, falsejeśli nie.
Używając tego, makeSymmDiffFunc(czytaj "funkcja tworzenia symetrycznej różnicy") zwraca nam nową funkcję:
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
To jest funkcja, której będziemy faktycznie używać. Przekazujemy mu dwie listy i znajduje elementy w pierwszej, a nie w drugiej, a następnie elementy w drugiej nie na pierwszej i łączy te dwie listy.
Jednak patrząc jeszcze raz, zdecydowanie mogłem wziąć wskazówkę z twojego kodu i całkiem uprościć główną funkcję, używając 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));
};
};
}());
complementużywa predykatu i zwraca elementy swojej pierwszej listy, a nie drugiej. To jest prostsze niż mój pierwszy przebieg z oddzielną containsfunkcją.
Wreszcie funkcja główna jest opakowana w natychmiast wywołane wyrażenie funkcyjne ( IIFE ), aby utrzymać funkcję wewnętrzną complementpoza zasięgiem globalnym.
Aktualizacja, kilka lat później
Teraz, gdy ES2015 stał się całkiem nieźle wszechobecny, sugerowałbym tę samą technikę, z dużo mniejszą liczbą schematów:
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"}