5
votes

Ramda: vérifier si deux tableaux sont égaux

J'apprends encore la programmation fonctionnelle en JavaScript et j'aime beaucoup utiliser Ramda.

J'ai deux tableaux. Je veux vérifier s'ils ont les mêmes valeurs, indépendamment de l'ordre. Je pensais que cela pouvait être fait avec est égal à . Mais apparemment

R.equals([1, 2], [2, 1]) // false

Existe-t-il un moyen efficace de vérifier si deux tableaux sont égaux? Mes tableaux sont constitués d'objets et peuvent contenir jusqu'à X * 10E4 valeurs si cela compte avec 1


0 commentaires

3 Réponses :


3
votes

Il existe de nombreuses façons d'y parvenir avec Ramda.

L'une d'elles me vient à l'esprit:

R.length([1,2]) === R.length([2,1]) && R.isEmpty(R.symmetricDifference([1,2], [2,1]))

modifier : en utilisant R.difference par opposition à R.symmetricDifference ne fonctionnerait pas, car le premier ne renvoie que les éléments de la première liste qui ne sont pas contenus dans la deuxième liste. p>

R. différence ([1,2], [2,1,3]) // -> []


0 commentaires

6
votes

J'utiliserais eqBy avec countBy :

Vous pouvez utiliser countBy pour créer un" profil " de votre tableau:

eqBy(countBy(identity), [1,2], [2,1])
//=> true

Ensuite, vous pouvez comparer les deux profils avec eqBy:

countBy(identity, [1, 2]);
//=> {"1": 1, "2": 1}

countBy(identity, [2, 1]);
//=> {"1": 1, "2": 1}

p>


2 commentaires

Hmm, votre solution renvoie un faux positif: const equalValues ​​= (arr1, arr2) => R.eqBy (R.countBy (R.identity), arr1, arr2); equalValues ​​([{foo: 'bar', baz: null}, {hi: 'ho'}], [{hello: 'world'}, {foo: 'bar', baz: null}])


Pour comparer des objets, la fonction de countBy doit être plus impliquée, j'en ai peur. Une option consiste à produire une signature unique pour chacun.



10
votes

La raison pour laquelle cela ne fonctionne pas comme ça - au-delà du fait que la fonction Ramda est nommée equals et non isEqual - c'est que les tableaux sont des conteneurs intrinsèquement ordonnés. [1, 2] est matériellement différent de [2, 1] .

Le conteneur standard non ordonné est le Set . Malheureusement, cela est basé sur l'égalité de référence, de sorte qu'il pourrait obtenir plusieurs copies d'éléments que Ramda considérerait comme égaux. La réponse la plus évidente ne fonctionnera donc pas correctement:

<script src="https://bundle.run/ramda@0.26.1"></script><script>
const {compose, isEmpty, symmetricDifference} = ramda;   </script>

car elle échouerait en raison d'une vérification de longueur dans ce cas:

const eqValues = compose(isEmpty, symmetricDifference)

console.log(eqValues(
  [{x: 1}, {x: 2}], 
  [{x: 1}, {x: 3}]
)) //=> false
console.log(eqValues(
  [{x: 1}, {x: 2}], 
  [{x: 2}, {x: 1}]
)) //=> true
console.log(eqValues(
  [{x: 1}, {x: 2}], 
  [{x: 2}, {x: 1}, {x: 1}]
)) //=> true

Ramda n'expose pas son type interne _Set - et peut-être devrait-il - mais il les utilise dans des fonctions telles que différence , et à travers cela dans symmetricDifference . Ce sont des fonctions appropriées pour tester des valeurs dont l'égalité des valeurs est en question.

Ma réponse serait donc similaire à celle des bogues, mais je la formulerais un peu différemment:

console.log(eqValues(
  [{x: 1}, {x: 2}, {x: 2}], 
  [{x: 2}, {x: 1}]
)) //=> false, but should be true, since {x: 2} is the same as {x: 2}
// ** Broken -- do not use **
const eqValues = (a1, a2) => R.equals(new Set(a1), new Set(a2))

console.log(eqValues(
  [{x: 1}, {x: 2}], 
  [{x: 1}, {x: 3}]
)) //=> false
console.log(eqValues(
  [{x: 1}, {x: 2}], 
  [{x: 2}, {x: 1}]
)) //=> true

Cependant, si vous devez tester les multiplicités, c'est-à-dire que arr1 contient deux copies de {x: 42} et arr2 n'en a qu'un, donc ils sont différents - alors j'utiliserais la réponse de customcommander.


4 commentaires

Merci pour votre réponse, j'ai corrigé l'erreur dans ma question. Les objets dans les tableaux sont tous uniques en raison de leurs identifiants uniques en tant que valeurs. Donc, vous répondez devrait fonctionner, non?


Les tableaux sont des conteneurs intrinsèquement ordonnés cette intuition pour les types dans un langage non typé comme Javascript est rare ici sur SO. C'est juste mon point de vue subjectif, cependant. +1


Votre implémentation est en fait la seule qui passe. customcommander renvoie un faux positif: const equalValues ​​= (arr1, arr2) => R.eqBy (R.countBy (R.identity), arr1, arr2); equalValues ​​([{foo: 'bar', baz: null}, {hi: 'ho'}], [{hello: 'world'}, {foo: 'bar', baz: null}])


@ J.Hesters: Oui, si les éléments du tableau sont garantis uniques, cela devrait fonctionner. Mais alors la première réponse que j'ai donnée fonctionnerait également dans ce cas.