How to create multidimensional arrays in Scala

This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 11.11, “How to Create Multidimensional Arrays in Scala.”

Problem

You need to create a multidimensional array in Scala, i.e., an array with two or more dimensions.

Scala Solution

There are two main solutions:

  • Use Array.ofDim to create a multidimensional array. You can use this approach to create arrays of up to five dimensions. With this approach you need to know the number of rows and columns at creation time.
  • Create arrays of arrays as needed.

Both approaches are shown in this solution.

Using Array.ofDim

Use the Array.ofDim method to create the array you need:

scala> val rows = 2
rows: Int = 2

scala> val cols = 3
cols: Int = 3

scala> val a = Array.ofDim[String](rows, cols)
a: Array[Array[String]] = Array(Array(null, null, null), Array(null, null, null))

After declaring the array, add elements to it:

a(0)(0) = "a"
a(0)(1) = "b"
a(0)(2) = "c"
a(1)(0) = "d"
a(1)(1) = "e"
a(1)(2) = "f"

Access the elements using parentheses, similar to a one-dimensional array:

scala> val x = a(0)(0)
x: String = a

Iterate over the array with a for loop:

scala> for {
     |   i <- 0 until rows
     |   j <- 0 until cols
     | } println(s"($i)($j) = ${a(i)(j)}")
(0)(0) = a
(0)(1) = b
(0)(2) = c
(1)(0) = d
(1)(1) = e
(1)(2) = f

To create an array with more dimensions, just follow that same pattern. Here’s the code for a three-dimensional array:

val x, y, z = 10
val a = Array.ofDim[Int](x,y,z)
for {
  i <- 0 until x
  j <- 0 until y
  k <- 0 until z
} println(s"($i)($j)($k) = ${a(i)(j)(k)}")

Using an array of arrays

Another approach is to create an array whose elements are arrays:

scala> val a = Array( Array("a", "b", "c"), Array("d", "e", "f") )
a: Array[Array[String]] = Array(Array(a, b, c), Array(d, e, f))

scala> a(0)
res0: Array[String] = Array(a, b, c)

scala> a(0)(0)
res1: String = a

This gives you more control of the process, and lets you create “ragged” arrays (where each contained array may be a different size):

scala> val a = Array(Array("a", "b", "c"), Array("d", "e"))
a: Array[Array[String]] = Array(Array(a, b, c), Array(d, e))

You can declare your variable as a var and create the same array in multiple steps:

scala> var arr = Array(Array("a", "b", "c"))
arr: Array[Array[String]] = Array(Array(a, b, c))

scala> arr ++= Array(Array("d", "e"))

scala> arr
res0: Array[Array[String]] = Array(Array(a, b, c), Array(d, e))

Note in this example that the variable arr was created as a var, which lets you assign the output from the ++= operator back to it. This gives the illusion that you’ve modified the contents of arr, but in reality, you’ve modified arr’s reference so it points at a new collection. (See Recipe 10.6, “Understanding Mutable Variables with Immutable Collections” for more information.)

Discussion

Decompiling the Array.ofDim solution helps to understand how this works behind the scenes. Create the following Scala class in a file named Test.scala:

class Test {
    val arr = Array.ofDim[String](2, 3)
}

If you compile that class with scalac, and then decompile it with a tool like JAD, you can see the Java code that’s created:

private final String arr[][];

Similarly, creating a Scala three-dimensional Array like this:

val arr = Array.ofDim[String](2, 2, 2)

results in a Java array like this:

private final String arr[][][];

As you might expect, the code generated by using the “array of arrays” approach is more complicated. This is a case where using a decompiler can help you understand how Scala works, i.e., what code it generates for you.

Finally, the Array.ofDim approach is unique to the Array class; there is no ofDim method on a List, Vector, ArrayBuffer, etc. But the “array of arrays” solution is not unique to the Array class. You can have a “list of lists,” “vector of vectors,” and so on.

I hope it has been helpful. All the best, Al.