简体   繁体   中英

Ramda: Check if two arrays are equal

I'm still learning functional programming in JavaScript and I enjoy using Ramda a lot.

I have two arrays. I want to check if they have the same values, independent of order. I thought this could be done with equals . But apparently

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

Is there an efficient way to check whether two arrays are equal? My arrays constist of objects and can hold up to X * 10E4 values if that matters with 1 < X < 10.

The reason it doesn't work like that -- beyond the fact that the Ramda function is named equals and not isEqual -- is that Arrays are intrinsically ordered containers. [1, 2] is materially different from [2, 1] .

The standard unordered container is the Set . Unfortunately that is based on reference equality, so it could get multiple copies of items Ramda would think of as equal. So the most obvious answer will not work properly:

// ** 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

because it would fail due to a length check in this case:

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}

Ramda does not expose its internal _Set type -- and perhaps it should -- but it uses them in such functions as difference , and through that in symmetricDifference . These are appropriate functions for testing values whose value equality is in question.

So my answer would be similar to the one from bugs, but I would phrase it a bit differently:

 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 
 <script src="https://bundle.run/ramda@0.26.1"></script><script> const {compose, isEmpty, symmetricDifference} = ramda; </script> 

However, if you need to test multiplicities -- that is, arr1 contains two copies of {x: 42} and arr2 only has one, so they're different -- then I would use the answer from customcommander.

I would use eqBy with countBy :

You can use countBy to build a "profile" of your array:

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

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

Then you can compare the two profiles with eqBy :

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

There are many ways to achieve this with Ramda

One that comes to mind is

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

edit : using R.difference as opposed to R.symmetricDifference wouldn't work, as the first one only returns the elements in the first list that are not contained in the second list.

R.difference([1,2], [2,1,3]) // -> []

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM