web-dev-qa-db-fra.com

Tableau de comparaison profonde d'objets avec lodash

J'ai 2 tableaux d'objets que je comparerais profondément avec lodash

Cependant, j'ai un problème avec:

> var x = [{a:1, b:2}, {c:3, d:4}];
> var y = [{b:2, a:1}, {d:4, c:3}];
> _.difference(x,y, _.isEqual);
[ { a: 1, b: 2 }, { c: 3, d: 4 } ]

Comment dois-je comparer pour voir que les deux sont égaux?

13
Archer

Vous pouvez utiliser differenceWith () avec un comparateur isEqual () , et invoquer isEmpty pour vérifier s'ils sont égaux ou non.

var isArrayEqual = function(x, y) {
  return _(x).differenceWith(y, _.isEqual).isEmpty();
};

var result1 = isArrayEqual(
  [{a:1, b:2}, {c:3, d:4}],
  [{b:2, a:1}, {d:4, c:3}]
);

var result2 = isArrayEqual(
  [{a:1, b:2, c: 1}, {c:3, d:4}],
  [{b:2, a:1}, {d:4, c:3}]
);

document.write([
  '<div><label>result1: ', result1, '</label></div>',
  '<div><label>result2: ', result2, '</label></div>',
].join(''));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.2/lodash.js"></script>

MISE À JOUR 22 juin 2018

Cette mise à jour répond au commentaire ci-dessous:

@ryeballar si l'un des tableaux n'est pas défini, il renvoie vrai. Comment résoudriez-vous cela? Merci d'avance mon pote

Comme indiqué dans la documentation differenceWith:

L'ordre et les références des valeurs de résultat sont déterminés par le premier tableau.

Cela signifie que tant que tous les éléments du premier tableau correspondront à tout le reste du second tableau, le tableau résultant de l'invocation differenceWith sera vide.

Une solution alternative qui résout vraiment le problème est d'utiliser xorWith() avec la même chaîne de fonctions que la solution ci-dessus.

var isArrayEqual = function(x, y) {
  return _(x).xorWith(y, _.isEqual).isEmpty();
};

var result1 = isArrayEqual(
  [{a:1, b:2}, {c:3, d:4}],
  [{b:2, a:1}, {d:4, c:3}]
);

var result2 = isArrayEqual(
  [{a:1, b:2, c: 1}, {c:3, d:4}],
  [{b:2, a:1}, {d:4, c:3}]
);

var result3 = isArrayEqual(
  [{a:1, b:2, c: 1}, {c:3, d:4}],
  [{b:2, a:1}, {d:4, c:3}, undefined]
);

console.log('result1:', result1);
console.log('result2:', result2);
console.log('result3:', result3);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
30
ryeballar

Je préfère le JS pur car je n'ai pas la patience d'apprendre le underscore ou le lodash. Donc j'invente quelque chose dont je rêve depuis longtemps. Le Object.prototype.compare(). La v0.0.2 ne fait qu'une comparaison superficielle mais adéquate pour cette question.

Object.prototype.compare = function(o){
  var ok = Object.keys(this);
  return typeof o === "object" && ok.length === Object.keys(o).length ? ok.every(k => this[k] === o[k]) : false;
};
var obj1 = {a:1,b:2,c:3},
    obj2 = {c:3,a:1,b:2},
    obj3 = {b:2,c:3,a:7};

document.write ("<pre>" + obj1.compare(obj2) + "</pre>\n");
document.write ("<pre>" + obj2.compare(obj3) + "</pre>\n");
document.write ("<pre>" + new Object({a:1, b:2, c:3}).compare({c:3,b:2,a:1,d:0}) + "</pre>\n");

Cool ... Alors, continuons avec la question ... Je suppose ... puisque nous avons déjà un Object.prototype.compare() il ne devrait y avoir absolument aucun mal à l'invention de Array.prototype.compare(). Permet de le rendre plus intelligent cette fois. Il doit distinguer les primitives des objets. Une autre chose est que les tableaux sont ordonnés; donc dans mon livre [1,2] n'est pas égal à [2,1]. Cela rend également le travail plus simple.

Object.prototype.compare = function(o){
  var ok = Object.keys(this);
  return typeof o === "object" && ok.length === Object.keys(o).length ? ok.every(k => this[k] === o[k]) : false;
};
Array.prototype.compare = function(a){
  return this.every((e,i) => typeof a[i] === "object" ? a[i].compare(e) : a[i] === e);
}
var x = [{a:1, b:2}, {c:3, d:4}],
    y = [{b:2, a:1}, {d:4, c:3}],
    a = [1,2,3,4,5],
    b = [1,2,3,4,5],
    p = "fourtytwo",
    r = "thirtyseven",
    n = 42,
    m = 37;
document.writeln(x.compare(y)); // the question is answered here
document.writeln(a.compare(b));
document.writeln(p.compare(r)); // these primitives end up at Object prototype
document.writeln(n.compare(m)); // so modify Object.prototype.compare () accordingly
3
Redu

Après la réponse de @ryeballar, si vous souhaitez uniquement importer des méthodes lodash spécifiques, vous pouvez utiliser cette notation:

import { isEmpty, isEqual, xorWith } from 'lodash';


export const isArrayEqual = (x, y) => isEmpty(xorWith(x, y, isEqual));

2
Anita