arraysscaladictionaryscala-collections

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


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?


Solution

  • 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.)