How to get the element index when mapping an array in Scala?

Ivan picture Ivan · Feb 4, 2012 · Viewed 35.9k times · Source

Let's consider a simple mapping example:


  val a = Array("One", "Two", "Three")
  val b = a.map(s => myFn(s))

What I need is to use not myFn(s: String): String here, but myFn(s: String, n: Int): String, where n would be the index of s in a. In this particular case myFn would expect the second argument to be 0 for s == "One", 1 for s == "Two" and 2 for s == "Three". How can I achieve this?

Answer

Rex Kerr picture Rex Kerr · Feb 4, 2012

Depends whether you want convenience or speed.

Slow:

a.zipWithIndex.map{ case (s,i) => myFn(s,i) }

Faster:

for (i <- a.indices) yield myFn(a(i),i)

{ var i = -1; a.map{ s => i += 1; myFn(s,i) } }

Possibly fastest:

Array.tabulate(a.length){ i => myFn(a(i),i) }

If not, this surely is:

val b = new Array[Whatever](a.length)
var i = 0
while (i < a.length) {
  b(i) = myFn(a(i),i)
  i += 1
}

(In Scala 2.10.1 with Java 1.6u37, if "possibly fastest" is declared to take 1x time for a trivial string operation (truncation of a long string to a few characters), then "slow" takes 2x longer, "faster" each take 1.3x longer, and "surely" takes only 0.5x the time.)