77
val a: Array[Int] = Array(1,2,4,5)
val b: Array[Int] = Array(1,2,4,5)
a==b // false

Is there a pattern-matching way to see if two arrays (or sequences) are equivalent?

Phil H
  • 19,928
  • 7
  • 68
  • 105
  • 1
    duplicate of http://stackoverflow.com/questions/2481149/why-does-array0-1-2-array0-1-2-not-return-the-expected-result and http://stackoverflow.com/questions/3737711/why-doesnt-the-array-equality-function-work-as-expected answer from those is to use `sameElements` – Dan D. Mar 22 '11 at 15:14
  • 1
    This _is_ a duplicate, but `sameElements` doesn't do the trick for nested arrays, because it's not recursive. Moritz' answer below is the appropriate one now (which should probably be added to the older answers). – Rex Kerr Mar 22 '11 at 15:24

6 Answers6

114

From Programming Scala:

Array(1,2,4,5).sameElements(Array(1,2,4,5))
sc_ray
  • 7,803
  • 11
  • 63
  • 100
109

You need to change your last line to

a.deep == b.deep

to do a deep comparison of the arrays.

Moritz
  • 14,144
  • 2
  • 56
  • 55
  • 20
    This is the canonical way to do it. But just a warning to the performance-hungry: this _does_ create an entire new collection on both sides, so it's not the most efficient possible way to do it. – Rex Kerr Mar 22 '11 at 15:26
  • 8
    @Rex yes, it does create a new collection, but this does not mean, that it is inefficient. Look at the implementation of the method `deep`. It creates a collection, that forwards all calls of the `apply` method to the original array. – E. Verda Mar 23 '11 at 14:54
  • 1
    @E. Verda - Hm, the implementation is not what I'd expected. But it does a pattern match for _every element_ of the array, which is expensive if it's an array of primitives, and for nested arrays it _re-wraps the array_ on every access. If the arrays are almost entirely different it's inexpensive; for matching close arrays, it's going to be expensive compared to a recursive non-constructive solution. – Rex Kerr Mar 23 '11 at 15:38
  • @LucaMolteni:do you mean `Array.equals`? That doesn't seem to provide a deep comparison. – mitchus May 09 '16 at 10:58
  • There is also `java.util.Objects.deepEquals` – matanster Jul 23 '16 at 09:03
  • 2
    @matanster `deepEquals` is deprecated in the latest versions. – Johnny Apr 12 '18 at 09:23
  • @stas Good to know. I wonder what else has changed in this regard. Any good Scala libraries for working with deeply nested structures? – matanster Apr 12 '18 at 12:38
  • if you want to compare arrays, regardless of the order of elements though, you should sort them first. `arr1.sorted == arr2.sorted` hope this will help. – belka Oct 19 '18 at 13:11
22
  a.corresponds(b){_ == _}

Scaladoc: true if both sequences have the same length and p(x, y) is true for all corresponding elements x of this wrapped array and y of that, otherwise false

The Archetypal Paul
  • 41,321
  • 20
  • 104
  • 134
  • 4
    Array is not a sequence http://www.scala-lang.org/api/current/index.html#scala.Array, so this will require some (probably implicit) redirections. – Basilevs Sep 06 '11 at 17:58
14

For best performance you should use:

java.util.Arrays.equals(a, b)

This is very fast and does not require extra object allocation. Array[T] in scala is the same as Object[] in java. Same story for primitive values like Int which is java int.

jwvh
  • 50,871
  • 7
  • 38
  • 64
jjuraszek
  • 151
  • 1
  • 3
  • 1
    I ran `val t0 = System.nanoTime(); val r = (java.util.Arrays.equals(a,b)) ; val t1 = System.nanoTime(); t1 - t0` on this sample code and very similar code for the other examples ... This option was way faster than the other examples. – codeaperature Mar 21 '18 at 20:08
5

As of Scala 2.13, the deep equality approach doesn't work and errors out:

val a: Array[Int] = Array(1,2,4,5)
val b: Array[Int] = Array(1,2,4,5)
a.deep == b.deep // error: value deep is not a member of Array[Int]

sameElements still works in Scala 2.13:

a sameElements b // true
Powers
  • 18,150
  • 10
  • 103
  • 108
2

It didn't look like most of the provided examples work with multidimensional arrays. For example

 val expected = Array(Array(3,-1,0,1),Array(2,2,1,-1),Array(1,-1,2,-1),Array(0,-1,3,4))
 val other = Array(Array(3,-1,0,1),Array(2,2,1,-1),Array(1,-1,2,-1),Array(0,-1,3,4))

    assert(other.sameElements(expected))

returns false, throws an assertion failure

deep doesn't seem to be a function defined on Array.

For convenience I imported scalatest matchers and it worked.

import org.scalatest.matchers.should.Matchers._
other should equal(expected)  
discord
  • 59
  • 10