J'ai deux séries de résultats comme ceci:
// Result 1
[
{ 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" }
]
// Result 2
[
{ 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"}
]
Le résultat final dont j'ai besoin est la différence entre ces tableaux - le résultat final devrait ressembler à ceci:
[{ value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan" }]
Est-il possible de faire quelque chose comme ça en JavaScript?
En utilisant uniquement JS natif, quelque chose comme ceci fonctionnera:
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"}]
function comparer(otherArray){
return function(current){
return otherArray.filter(function(other){
return other.value == current.value && other.display == current.display
}).length == 0;
}
}
var onlyInA = a.filter(comparer(b));
var onlyInB = b.filter(comparer(a));
result = onlyInA.concat(onlyInB);
console.log(result);
Vous pouvez utiliser Array.prototype.filter()
en combinaison avec Array.prototype.some()
.
Voici un exemple (en supposant que vos tableaux sont stockés dans les variables result1
et result2
):
//Find values that are in result1 but not in result2
var uniqueResultOne = result1.filter(function(obj) {
return !result2.some(function(obj2) {
return obj.value == obj2.value;
});
});
//Find values that are in result2 but not in result1
var uniqueResultTwo = result2.filter(function(obj) {
return !result1.some(function(obj2) {
return obj.value == obj2.value;
});
});
//Combine the two arrays of unique entries
var result = uniqueResultOne.concat(uniqueResultTwo);
J'adopte une approche légèrement plus générale, bien que ses idées soient similaires à celles 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 propriété $$hashKey
, mais ce pourrait être n'importe quoi) et renvoie 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 par rapport à l'approche de Cerebrus (comme le fait l'approche de Kasper Moerch) en ce sens qu'il s'échappe tôt; s'il trouve une correspondance, il ne se soucie pas de vérifier le reste de la liste. Si j’avais une fonction curry
, je le ferais un peu différemment, mais cela fonctionne bien.
Un commentaire demandait une explication plus détaillée pour les débutants. Voici une tentative.
Nous passons 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
, on peut l'appeler une "fonction de prédicat", mais ce n'est que de la terminologie. Le point principal est que makeSymmDiffFunc
est configuré avec une fonction qui accepte deux objets et renvoie true
si nous les considérons comme égaux, false
si nous ne le faisons pas.
En utilisant cela, makeSymmDiffFunc
(lire "créer 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 allons réellement utiliser. On lui passe deux listes et on 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 cependant, j'aurais certainement pu prendre exemple sur 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 fonction contains
séparée.
Enfin, la fonction principale est encapsulée dans une expression de fonction immédiatement invoquée (IIFE) afin de conserver la fonction complement
interne en dehors de la portée globale.
Mise à jour, quelques années plus tard
Maintenant que ES2015 est devenu assez répandu, je suggérerais 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"}
import differenceBy from 'lodash/differenceBy'
const myDifferences = differenceBy(Result1, Result2, 'value')
Cela renverra la différence entre deux tableaux d'objets, en utilisant la clé value
pour les comparer. Notez que deux choses avec la même valeur ne seront pas retournées, car les autres clés sont ignorées.
Ceci fait partie de lodash .
Vous pouvez créer un objet avec des clés comme valeur unique correspondant à chaque objet du tableau, puis filtrer chaque tableau en fonction de l'existence de la clé dans l'objet de l'autre. Cela réduit la complexité de l'opération.
ES6
let 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"}];
let 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"}];
let valuesA = a.reduce((a,{value}) => Object.assign(a, {[value]:value}), {});
let valuesB = b.reduce((a,{value}) => Object.assign(a, {[value]:value}), {});
let result = [...a.filter(({value}) => !valuesB[value]), ...b.filter(({value}) => !valuesA[value])];
console.log(result);
ES5
var 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"}];
var 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 valuesA = a.reduce(function(a,c){a[c.value] = c.value; return a; }, {});
var valuesB = b.reduce(function(a,c){a[c.value] = c.value; return a; }, {});
var result = a.filter(function(c){ return !valuesB[c.value]}).concat(b.filter(function(c){ return !valuesA[c.value]}));
console.log(result);
Je pense que la solution @Cerbrus est parfaite. J'ai implémenté la même solution mais extrait le code répété dans sa propre fonction (DRY).
function filterByDifference(array1, array2, compareField) {
var onlyInA = differenceInFirstArray(array1, array2, compareField);
var onlyInb = differenceInFirstArray(array2, array1, compareField);
return onlyInA.concat(onlyInb);
}
function differenceInFirstArray(array1, array2, compareField) {
return array1.filter(function (current) {
return array2.filter(function (current_b) {
return current_b[compareField] === current[compareField];
}).length == 0;
});
}
Pour ceux qui aiment les solutions one-liner dans ES6, quelque chose comme ceci:
const arrayOne = [
{ 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" },
];
const arrayTwo = [
{ 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"},
];
const results = arrayOne.filter(({ value: id1 }) => !arrayTwo.some(({ value: id2 }) => id2 === id1));
console.log(results);
J'ai trouvé cette solution en utilisant un filtre et d'autres.
resultFilter = (firstArray, secondArray) => {
return firstArray.filter(firstArrayItem =>
!secondArray.some(
secondArrayItem => firstArrayItem._user === secondArrayItem._user
)
);
};
La plupart des réponses ici sont plutôt complexes, mais la logique derrière cela n’est-elle pas assez simple?
const getArraysDifference = (longerArray, array2) => {
const difference = [];
longerArray.forEach(el1 => { /*1*/
el1IsPresentInArr2 = array2.some(el2 => el2.value === el1.value); /*2*/
if (!el1IsPresentInArr2) { /*3*/
difference.Push(el1); /*4*/
}
});
return difference;
}
O (n ^ 2) complexité.
J'ai créé un diff généralisé qui compare 2 objets de tout type et peut exécuter un gestionnaire de modifications Gist.github.com/bortunac "diff.js" Un exemple d'utilisation:
old_obj={a:1,b:2,c:[1,2]}
now_obj={a:2 , c:[1,3,5],d:55}
donc la propriété a est modifiée, b est supprimée, c modifiée, d est ajoutée
var handler=function(type,pointer){
console.log(type,pointer,this.old.point(pointer)," | ",this.now.point(pointer));
}
maintenant utiliser comme
df=new diff();
df.analize(now_obj,old_obj);
df.react(handler);
la console montrera
mdf ["a"] 1 | 2
mdf ["c", "1"] 2 | 3
add ["c", "2"] undefined | 5
add ["d"] undefined | 55
del ["b"] 2 | undefined