How can I use map and receive an index as well in Scala?

Viewed 75780

Is there any List/Sequence built-in that behaves like map and provides the element's index as well?

8 Answers

I believe you're looking for zipWithIndex?

scala> val ls = List("Mary", "had", "a", "little", "lamb")
scala> ls.zipWithIndex.foreach{ case (e, i) => println(i+" "+e) }
0 Mary
1 had
2 a
3 little
4 lamb

From: http://www.artima.com/forums/flat.jsp?forum=283&thread=243570

You also have variations like:

for((e,i) <- List("Mary", "had", "a", "little", "lamb").zipWithIndex) println(i+" "+e)

or:

List("Mary", "had", "a", "little", "lamb").zipWithIndex.foreach( (t) => println(t._2+" "+t._1) )

There is CountedIterator in 2.7.x (which you can get from a normal iterator with .counted). I believe it's been deprecated (or simply removed) in 2.8, but it's easy enough to roll your own. You do need to be able to name the iterator:

val ci = List("These","are","words").elements.counted
scala> ci map (i => i+"=#"+ci.count) toList
res0: List[java.lang.String] = List(These=#0,are=#1,words=#2)

Or, assuming your collection has constant access time, you could map the list of indexes instead of the actual collection:

val ls = List("a","b","c")
0.until(ls.length).map( i => doStuffWithElem(i,ls(i)) )

There are two ways of doing this.

ZipWithIndex: Creates a counter automatically starting with 0.

  // zipWithIndex with a map.
  val days = List("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
  days.zipWithIndex.map {
        case (day, count) => println(s"$count is $day")
  }
  // Or use it simply with a for.
  for ((day, count) <- days.zipWithIndex) {
        println(s"$count is $day")
  }

Output of both code will be:

0 is Sun
1 is Mon
2 is Tue
3 is Wed
4 is Thu
5 is Fri
6 is Sat

Zip: Use zip method with a Stream to create a counter. This gives you a way to control the starting value.

for ((day, count) <- days.zip(Stream from 1)) {
  println(s"$count is $day")
}

Result:

1 is Sun
2 is Mon
3 is Tue
4 is Wed
5 is Thu
6 is Fri
7 is Sat

Use .map in .zipWithIndex with Map data structure

val sampleMap = Map("a" -> "hello", "b" -> "world", "c" -> "again")

val result = sampleMap.zipWithIndex.map { case ((key, value), index) => 
    s"Key: $key - Value: $value with Index: $index"
}

Results

 List(
       Key: a - Value: hello with Index: 0, 
       Key: b - Value: world with Index: 1, 
       Key: c - Value: again with Index: 2
     )

If you require searching the map values as well (like I had to):

val ls = List("a","b","c")
val ls_index_map = ls.zipWithIndex.toMap 
Related