10.11. Using zipWithIndex or zip to Create Loop Counters

Problem

You want to loop over a sequential collection, and you’d like to have access to a counter in the loop, without having to manually create a counter.

Solution

Use the zipWithIndex or zip methods to create a counter automatically. Assuming you have a sequential collection of days:

val days = Array("Sunday", "Monday", "Tuesday", "Wednesday",
                 "Thursday", "Friday", "Saturday")

you can print the elements in the collection with a counter using the zipWithIndex and foreach methods:

days.zipWithIndex.foreach {
  case(day, count) => println(s"$count is $day")
}

As you’ll see in the Discussion, this works because zipWithIndex returns a series of Tuple2 elements in an Array, like this:

Array((Sunday,0), (Monday,1), ...

and the case statement in the foreach loop matches a Tuple2.

You can also use zipWithIndex with a for loop:

for ((day, count) <- days.zipWithIndex) {
  println(s"$count is $day")
}

Both loops result in the following output:

0 is Sunday
1 is Monday
2 is Tuesday
3 is Wednesday
4 is Thursday
5 is Friday
6 is Saturday

When using zipWithIndex, the counter always starts at 0. You can also use the zip method with a Stream to create a counter. This gives you a way to control the starting value:

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

Discussion

When zipWithIndex is used on a sequence, it returns a sequence of Tuple2 elements, as shown in this example:

scala> val list = List("a", "b", "c") list: ...

Get Scala Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.