Utilisation de lodash pour comparer des tableaux (existence d'éléments sans ordre)

126

Je sais que je peux le faire en utilisant des boucles, mais j'essaie de trouver une façon élégante de le faire:

J'ai deux tableaux:

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];

Je veux utiliser lodashpour confirmer que les deux tableaux ci-dessus sont identiques. Par «le même», je veux dire qu'il n'y a aucun élément array1qui ne soit contenu dans array2.

En termes de vérification de l'égalité entre ces éléments:

['a', 'b'] == ['b', 'a'] 

ou

['a', 'b'] == ['a', 'b'] 

Les deux fonctionnent puisque les lettres seront toujours en ordre.

pQuestions123
la source

Réponses:

224

Si vous triez le tableau externe, vous pouvez l'utiliser _.isEqual()car le tableau interne est déjà trié.

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];
_.isEqual(array1.sort(), array2.sort()); //true

Notez que cela .sort()fera muter les tableaux. Si c'est un problème pour vous, faites d'abord une copie en utilisant (par exemple) .slice()ou l'opérateur d'étalement ( ...).

Ou, faites comme le recommande Daniel Budick dans un commentaire ci-dessous:

_.isEqual(_.sortBy(array1), _.sortBy(array2))

Lodash ne sortBy()fera pas muter le tableau.

Trott
la source
6
Tenez compte du fait que array.sort () mute le tableau d'origine. Peut-être que celui-ci pourrait être meilleur: var array1 = [['a', 'b'], ['b', 'c']]; var array2 = [['b', 'c'], ['a', 'b']]; _.isEqual ([... tableau1] .sort (), [... tableau2] .sort ()); // true
Yaniv Efraim
3
Ajout de deux phrases notant que .sort()mute et suggérant des options pour la copie en premier si cela pose un problème pour l'utilisateur.
Trott
6
Si vous utilisez déjà lodash, vous pouvez simplement _.isEqual(_.sortBy(array1), _sortBy(array2))éviter la mutation.
Daniel Budick
1
@DanielBudick Merci! J'ai ajouté cela à la réponse. Excellente suggestion.
Trott
33

Vous pouvez utiliser des lodashs xorpour cela

doArraysContainSameElements = _.xor(arr1, arr2).length === 0

Si vous considérez que le tableau [1, 1] est différent du tableau [1], vous pouvez améliorer les performances un peu comme ceci:

doArraysContainSameElements = arr1.length === arr2.length === 0 && _.xor(arr1, arr2).length === 0
Stéphan Hoyer
la source
1
Les tableaux doivent de toute façon être triés.
Sovattha Sok
1
Cela devrait être le meilleur moyen pour une version plus récente
Leonardo
@Sovattha Sok Les tableaux n'ont pas besoin d'être triés. Faire vous _.xor([3,4], [4,3]).length == 0rendra vrai.
Nikolay
1
Un mot d'avertissement: cette technique fonctionne bien pour les "petits" tableaux, mais cela peut être une performance pénible et en termes de mémoire si vos tableaux sont énormes et sont principalement différents parce que _.xor () continuera à aller au-delà de la première différence. En d'autres termes, il ne revient pas rapidement sur la première différence détectée.
XDS
6

Par «le même», je veux dire qu'il n'y a aucun élément dans array1 qui n'est pas contenu dans array2.

Vous pouvez utiliser Aplatir () et la différence () pour ce qui fonctionne bien si vous ne vous inquiétez pas s'il y a des éléments dans array2ce ne sont pas dans array1. On dirait que vous demandez si array1 est un sous-ensemble de array2 ?

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];

function isSubset(source, target) {
    return !_.difference(_.flatten(source), _.flatten(target)).length;
}

isSubset(array1, array2); // → true
array1.push('d');
isSubset(array1, array2); // → false
isSubset(array2, array1); // → true
Adam Boduch
la source
4

Il y a déjà des réponses ici, mais voici mon implémentation JS pure. Je ne sais pas si c'est optimal, mais c'est sûr que c'est transparent, lisible et simple.

// Does array a contain elements of array b?
const contains = (a, b) => new Set([...a, ...b]).size === a.length
const isEqualSet = (a, b) => contains(a, b) && contains(b, a)

La raison en contains()est que si acontient tous les éléments de b, les mettre dans le même ensemble ne changerait pas la taille.

Par exemple, si const a = [1,2,3,4]et const b = [1,2], alors new Set([...a, ...b]) === {1,2,3,4}. Comme vous pouvez le voir, l'ensemble résultant a les mêmes éléments que a.

À partir de là, pour le rendre plus concis, nous pouvons le résumer comme suit:

const isEqualSet = (a, b) => {
  const unionSize = new Set([...a, ...b])
  return unionSize === a.length && unionSize === b.length
}
J.Ko
la source
1

PURE JS (fonctionne également lorsque les tableaux et sous-tableaux ont plus de 2 éléments avec un ordre arbitraire). Si les chaînes contient l' ,utilisation comme join('-')caractère Parametr (peut être utf) qui ne sont pas utilisés dans les chaînes

array1.map(x=>x.sort()).sort().join() === array2.map(x=>x.sort()).sort().join()

Kamil Kiełczewski
la source
0

Nous pouvons utiliser la _.differencefonction pour voir s'il y a une différence ou non.

function isSame(arrayOne, arrayTwo) {
   var a = _.unique(arrayOne),
       b = _.unique(arrayTwo);

   if (a.length <= b.length) {
      a = arrayTwo;
      b = arrayOne;
      return _.isEmpty(_.difference(a.sort(), b.sort()));
   } else {
      return false;
   }

}

// examples
console.log(isSame([1, 2, 3], [1, 2, 3])); // true
console.log(isSame([1, 2, 4], [1, 2, 3])); // false
console.log(isSame([1, 2], [2, 3, 1])); // false
console.log(isSame([2, 3, 1], [1, 2])); // false

// Test cases pointed by Mariano Desanze, Thanks.
console.log(isSame([1, 2, 3], [1, 2, 2])); // false
console.log(isSame([1, 2, 2], [1, 2, 2])); // true
console.log(isSame([1, 2, 2], [1, 2, 3])); // false

J'espère que cela t'aidera.

Amitesh
la source
5
Faux, votre fonction sera truepourconsole.log(isSame([1,2], [2,3,1]));
David Lin
3
Merci @DavidLin de le signaler. J'ai fait les changements pour considérer ce cas. Merci et désolé pour la gêne occasionnée.
Amitesh le
2
vous n'avez pas besoin de changer de place pour a et b si les longueurs ne sont pas les mêmes. Si les longueurs diffèrent, elles ne peuvent pas être déjà les mêmes, donc if (arrayOne.lenght! == arrayTwo.lenght) return false;
Alex
1
-1 Inutile d'avoir ceux aet les bvariables. Vous n'utilisez ces variables dans la partie, et la première chose que vous faites il y a défaussez ces valeurs chargées à la ligne 2. Je pense que la seule ligne suivante fonctionne exactement le même: . Et le peut également être amélioré en . if-thenreturn arrayOne.length <= arrayTwo.length && _.isEmpty(_.difference(arrayTwo.sort(), arrayTwo.sort());<====
Mariano Desanze
1
Et _.differencerenverra les éléments manquants du 1er argument, mais pas les éléments manquants dans le 2ème. Donc , cela va revenir correctement truelorsque vous répétez les articles le 1er en 2ème: isSame([1, 2, 3], [1, 2, 2]).
Mariano Desanze
0

Edit: J'ai manqué l'aspect multidimensionnel de cette question, donc je laisse ceci ici au cas où cela aiderait les gens à comparer des tableaux unidimensionnels

C'est une vieille question, mais j'avais des problèmes avec la vitesse d'utilisation de .sort()ou sortBy(), alors j'ai utilisé ceci à la place:

function arraysContainSameStrings(array1: string[], array2: string[]): boolean {
  return (
    array1.length === array2.length &&
    array1.every((str) => array2.includes(str)) &&
    array2.every((str) => array1.includes(str))
  )
}

Il était destiné à échouer rapidement, et pour mes besoins fonctionne bien.

charliematters
la source
La dernière vérification est-elle vraiment nécessaire? array1.every((str) => array2.includes(str))Cela devrait suffire. Aussi l'OP voulait utiliser lodash, vous devriez au moins dire pourquoi vous proposez une solution vanillaJS (... maintenant que nous avons tout et inclut ...). Veuillez également fournir un exemple pour appliquer votre fonction au problème fourni (tableaux à 2 dimensions).
line-o
C'est un bon point - je n'ai pas abordé l'aspect multidimensionnel de celui-ci, pas l'exigence de lodash. J'ai pensé qu'il serait utile que quiconque cherche (comme je l'ai fait) pour lodash methods to compare arrays without considering ordervoir une alternative en Javascript moderne. La deuxième vérification est nécessaire car arraysContainSameStrings(['1', '2', '2'], ['1', '2', '3'])elle retournerait vrai autrement. Je vais le laisser ici, car cela pourrait aider, mais j'apprécie de ne pas avoir répondu à la question
charliematters