J'adopte une approche légèrement plus générale, bien que des idées similaires aux approches de @Cerbrus et @Kasper Moerch . Je crée une fonction qui accepte un prédicat pour déterminer si deux objets sont égaux (ici nous ignorons la $$hashKey
propriété, mais cela pourrait être n'importe quoi) et retourne une fonction qui calcule la différence symétrique de deux listes en fonction de ce prédicat:
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"}
Il a un avantage mineur sur l'approche de Cerebrus (tout comme l'approche de Kasper Moerch) en ce qu'il s'échappe tôt; s'il trouve une correspondance, il ne prend pas la peine de vérifier le reste de la liste. Si j'avais uncurry
fonction à portée de main, je le ferais un peu différemment, mais cela fonctionne très bien.
Explication
Un commentaire demandait une explication plus détaillée pour les débutants. Voici une tentative.
On passe la fonction suivante à makeSymmDiffFunc
:
function(x, y) {
return x.value === y.value && x.display === y.display;
}
Cette fonction est la façon dont nous décidons que deux objets sont égaux. Comme toutes les fonctions qui retournent true
ou false
, cela peut être appelé une "fonction de prédicat", mais ce n'est que de la terminologie. Le point principal est qu'il makeSymmDiffFunc
est configuré avec une fonction qui accepte deux objets et retourne true
si nous les considérons égaux, false
sinon.
En utilisant cela, makeSymmDiffFunc
(lire "faire une fonction de différence symétrique") nous renvoie une nouvelle fonction:
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
C'est la fonction que nous utiliserons réellement. On lui passe deux listes et il trouve les éléments dans la première pas dans la seconde, puis ceux dans la seconde pas dans la première et on combine ces deux listes.
En y repensant, j'aurais certainement pu s'inspirer de votre code et simplifier un peu la fonction principale en utilisant 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
utilise le prédicat et renvoie les éléments de sa première liste pas dans sa seconde. C'est plus simple que mon premier passage avec une contains
fonction séparée .
Enfin, la fonction principale est enveloppée dans une expression de fonction immédiatement appelée ( IIFE ) pour garder la complement
fonction interne hors de la portée globale.
Mise à jour, quelques années plus tard
Maintenant que ES2015 est devenu assez omniprésent, je suggère la même technique, avec beaucoup moins de passe-partout:
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"}