Making array generation more functional

I have a problem of writing this code in a more functional fashion

import scala.util.Random

val v =  Vector.fill(5)(Random.nextInt(100))
println(v)

val m = Array.fill[Int](10, 10)(0)

def populateMatrix(x: Int): Unit = m(x/10)(x%10) += 1

v.map(x => populateMatrix(x))

m foreach { row => row foreach print; println }

I would prefer something like

m=v.map(...)

Have you tried using ArraySeq.tabulate?

@BalmungSan I do not see how it can be useful :confused:. If the length of v is n and the dimension of the matrix is N the complexity of my procedural approach is $O(n)$, whereas the complexity of tabulate would be $O(N^2)$.

also asked at Functional way to build a matrix from the list in scala - Stack Overflow

Array is not in the functional realm to start with, so one cannot really expect an elaborate functional API on top of it. I also cannot imagine a reasonably generic method on Vector that might yield a nested Array of arbitrary size out of the box.

BTW, you are already tabulating - #fill() is implemented in terms of #tabulate().

If you really want to keep on working with Array, implement the functionality you want for reuse, e.g.

def sparse[T : ClassTag](w: Int, h: Int)(inits: Vector[(Int, Int, T => T)]): Array[Array[T]] = {
  val m = Array.ofDim[T](w, h)
  inits.foreach { case (x, y, f) => m(x)(y) = f(m(x)(y)) }
  m
}
val m = sparse[Int](10, 10)(v.map(i => (i / 10, i % 10, _ + 1)))

…and consider hiding it behind a thin wrapper type.

For linear algebra applications, you might alternatively look into libraries such as Breeze.

2 Likes

@sangamon I like your solution very much. But can you please explain what “hiding it behind a thin wrapper type” explicitly mean.

Well, an Array is not a matrix. First, you’ll want a place to put additional, matrix-specific methods that Array is lacking: addition, scalar multiplication,… A custom class wrapping an Array seems to be a good candidate for this. Of course you could just tack this functionality onto Array by means of implicit classes (or extension methods in Scala 3). But…

…then there’s additional constraints on matrices over arrays - the obvious first candidate being that you want matrices to be rectangular, whereas an Array[Array[Int]] can basically have any shape. (There may also be methods on Array that are inappropriate to invoke on a matrix.) And that’s, at the latest, where I’d start considering introducing a custom class wrapping the matrix Array (with a private constructor, so instances can only be created from methods on the wrapper class or factory methods on its companion object), e.g.

class Matrix[T : Numeric : ClassTag] private (private val arr: Array[Array[T]])
  // ...
}

The downside, of course, is that you’ll have to explicitly expose any functionality you want to be available on matrices as custom methods, even if it’s handily available on Array already. But I’d think the gains from the guarantees introduced by the custom type outweigh these nuisances in the long run.

That being said, I wouldn’t venture into this specific area. If I needed matrix computations, I’d look for a linear algebra library. If this is about getting more familiar with Scala programming, I’d think there’s better domains that don’t require fiddling with mutable arrays…

2 Likes