1. Overview

In this tutorial, we’ll see how we can iterate through a collection while accessing the index in Scala.

2. Using the zip Method

Scala offers some possibilities to access the iteration index. The most naive solution uses the zip method to join the original list with another containing the indexes. Using this approach, we can manually create another list with the indexes and zip both lists:

scala> val lst = List("a","b","c","d","e")
val lst: List[String] = List(a, b, c, d, e)

scala> lst.zip(List(0,1,2,3,4,5,6,7)).foreach(println)
(a,0)
(b,1)
(c,2)
(d,3)
(e,4)

Notice that the zip method returns a list that joins the original lists. But if both have a different number of elements, then the resulting list will be as small as the smallest list passed. We can see that in our previous example: we have a list with 5 elements, but the second has 8 elements. The resulting joined list only has 5 elements as well, and it discarded the extra elements of the longer list.

3. Using zip with Ranges

The previous was an okay example. But in real life, we don’t know the size of the list. We can overcome that using Ranges. Ranges can be iterated just like normal Lists, but they have the advantage that they do not store all elements in memory. We can create a Range using the until method:

scala> 0 until 5
val res0: scala.collection.immutable.Range = Range 0 until 5

scala> (0 until 5).toList
val res1: List[Int] = List(0, 1, 2, 3, 4)

Now let’s use a Range in our zip example:

scala> lst.zip(0 until lst.size).foreach(println)
(a,0)
(b,1)
(c,2)
(d,3)
(e,4)

And now we have a list with the index.

4. Accessing the Tuple

As you may have noticed, the .zip method creates a list of pairs. If you need to access each part of the tuple, Scala also allows you to do it very easily. Let’s try to iterate through the zipped list accessing both the original element and the index. For this example, we’ll just print a string:

scala> lst.zip(0 until lst.size).foreach(tuple => println(s"original element: ${tuple._1} => index: ${tuple._2}"))
original element: a => index: 0
original element: b => index: 1
original element: c => index: 2
original element: d => index: 3
original element: e => index: 4

Or even better, using the scala case statement:

scala> lst.zip(0 until lst.size).foreach{ case (elem, idx) => println(s"original element: ${elem} => index: ${idx}")}
original element: a => index: 0
original element: b => index: 1
original element: c => index: 2
original element: d => index: 3
original element: e => index: 4

5. Using zipWithIndex

But all of this seems a bit of a waste. If you look carefully, we are creating a second list to hold the indexes, just to be zipped into a third list. It’s ok for our example, but if we have big lists may, then this approach represents a huge memory overload. Furthermore, it seems too much work for such a common operation.

Scala offers a better way for this, using the .zipWithIndex method:

scala> lst.zipWithIndex.foreach{ case (elem, idx) => println(s"original element: ${elem} => index: ${idx}")}
original element: a => index: 0
original element: b => index: 1
original element: c => index: 2
original element: d => index: 3
original element: e => index: 4

Using the zipWithIndex method, we avoid creating an auxiliary list just to hold the indexes. And the code became much cleaner.

6. Conclusion

In this article, we saw some solutions to iterate through a collection while accessing the index in Scala.