13

I want to work with an immutable indexed multidimensional array. The structure that makes sense is a Vector of Vectors.

scala> val v = Vector[Vector[Int]](Vector[Int](1,2,3), Vector[Int](4,5,6), Vector[Int](7,8,9))
v: scala.collection.immutable.Vector[Vector[Int]] = Vector(Vector(1, 2, 3), Vector(4, 5, 6), Vector(7, 8, 9))

It would be nice to create an empty array just by specifying the dimensions, like you can with Array.ofDim.

scala> a = Array.ofDim[Int](3,3)
a: Array[Array[Int]] = Array(Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0))

However, there is no Vector.ofDim, function, and I can't find an equivalent.

Is there an equivalent of Array.ofDim for immutable objects? If not, why not?

om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
W.P. McNeill
  • 16,336
  • 12
  • 75
  • 111
  • It's for a program that solves Sudoku puzzles. A partial solution is represented as an nxn array of `Option[Int]`. Given a partial solution _p_, the program can hypothesize another one _p'_ by putting integers into the array. Because each _p_ may generate multiple _p'_ s, I want each partial solution to be immutable. My options appear to either be 1) represent the numbers with a private `Array` 2) represent the numbers with a `Vector`. (2) seems more in the functional style, but creating `Vector`s of `Vector`s is awkward. – W.P. McNeill Oct 12 '12 at 22:06
  • You can represent multi-dimensional arrays/lists using single dimensions. – pedrofurla Oct 13 '12 at 00:17
  • 1
    Prepare for some fun trying to update cells in a multi-dimensional Vector. Probably easiest is to have a utility method: `def update[T](v: Vector[Vector[T]])(c1: Int, c2: Int)(newVal: T) = v.updated(c1, v(c1).updated(c2, newVal))`. Or if you need higher dimensions copy and paste from http://stackoverflow.com/a/12612908/770361. – Luigi Plinge Oct 13 '12 at 00:33

3 Answers3

19

Each standard collection class has a companion object with factory methods, including fill. By example:

Vector.fill(3, 3)( 0 )

See the relevant scaladoc.

Régis Jean-Gilles
  • 32,541
  • 5
  • 83
  • 97
  • Link gives 404. The current link is (2016-11-25): http://www.scala-lang.org/api/current/scala/collection/immutable/Vector.html – eddy147 Nov 25 '16 at 14:32
  • I updated the link (it was just badly parsed by SO). It turns out that the current scaladoc still does not mention `fill` so I've stuck to scala 2.9.1. – Régis Jean-Gilles Nov 25 '16 at 17:14
  • Not sure why you can't see it, but `fill` is there, and has been for a long while: http://www.scala-lang.org/api/current/scala/collection/immutable/Vector$.html#fill[A](n1:Int,n2:Int)(elem:=>A):CC[CC[A]] It's in the companion object, of course – The Archetypal Paul Nov 25 '16 at 18:57
  • Oh scratch that, you're right. I was pretty sure to have clicked on the big icon to go to the object's page so I don't know how I missed it. Thanks, I'll point to the new docs then. – Régis Jean-Gilles Nov 28 '16 at 08:55
15

There is a creation method called tabulate that lets you set the contents based on the index:

scala> Vector.tabulate(3,3){ (i,j) => 3*i+j+1 }
res0: scala.collection.immutable.Vector[scala.collection.immutable.Vector[Int]] =
Vector(Vector(1, 2, 3), Vector(4, 5, 6), Vector(7, 8, 9))

If you just need zeros (or some other constant), you can use fill instead:

scala> Vector.fill(3,3)(0)
res1: scala.collection.immutable.Vector[scala.collection.immutable.Vector[Int]] =
Vector(Vector(0, 0, 0), Vector(0, 0, 0), Vector(0, 0, 0))
Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
5

You can use fill:

scala> Vector.fill( 3 )( Vector.fill(3)(0) )
res1: scala.collection.immutable.Vector[scala.collection.immutable.Vector[Int]] = 
        Vector(Vector(0, 0, 0), Vector(0, 0, 0), Vector(0, 0, 0))
paradigmatic
  • 40,153
  • 18
  • 88
  • 147