Scala: For loop version 2.0
Most programmers would have introduced to the iteration world through the for loop. It has been simple and straight forward though these years. But lately our requirements out of this iterative control structure bas been increasing(functional paradigm, cartesian product, etc). Scala’s for loop has evolved to a next level to quench our thirst.
Basic
The basic functionality of a for loop is to iterate. Here is how you iterate from 1 to 10 using Scala’s for loop
scala> for(i <- 1 to 3)
| println(i)
1
2
3
The left-arrow <- operator is called a generator as it generates individual values for the range or the collection on the right hand side. For loop can also be used to iterate over collections
scala> for(i <- List("world", "galaxy", "universe"))
| println("hello "+ i + "!!")
hello world!!
hello galaxy!!
hello universe!!
Multiple generators
Scala lets you have multiple generators in your for loop. When you have multiple generators, the loop iterators for both the generators.
scala> val starks = List("Robb", "Sansa", "Arya")
starks: List[String] = List(Robb, Sansa, Arya)scala> val lannisters = List("Cersei", "Jaime","Tywin")
lannisters: List[String] = List(Cersei, Jaime, Tywin)scala> for(stark <- starks; lannister <- lannisters)
| println(stark + " Stark hates " + lannister + " Lannister")
Robb Stark hates Cersei Lannister
Robb Stark hates Jaime Lannister
Robb Stark hates Tywin Lannister
Sansa Stark hates Cersei Lannister
Sansa Stark hates Jaime Lannister
Sansa Stark hates Tywin Lannister
Arya Stark hates Cersei Lannister
Arya Stark hates Jaime Lannister
Arya Stark hates Tywin Lannister
Think of the previous example as a double for loop. The output is the cartesian product of both the collections.
Guards (Filtering)
Scala also lets you to have guards for your iteration i.e. you can filter your collection prior to the iteration
scala> for{stark <- starks; lannister <- lannisters;
| if stark.startsWith("R")
| }
| println(stark + " Stark hates " + lannister + " Lannister")
Robb Stark hates Cersei Lannister
Robb Stark hates Jaime Lannister
Robb Stark hates Tywin Lannister
As seen above both {} and () can be used interchangeably but the convention is to use {} for multi lines and () for single line.
Yield
By using yield keyword, you can return the values from a for loop. This was the functional paradigm, that I was talking about earlier. This helps us to separate the computation which makes our code much more reusable.
val multipledByThree = for(i <- List(1,2,3)) yield i * 3
multipledByThree: List[Int] = List(3, 6, 9)
If you want to have a side effect along with your yield, you can do the following
scala> val multipledByThree = for(i <- List(1,2,3)) yield {
| println(i)
| i * 3
| }
1
2
3
multipledByThree: List[Int] = List(3, 6, 9)scala> println(multipledByThree)
List(3, 6, 9)
Variables declared inside a for loop are of type val, hence reassignment will throw an error
scala> for {i <- 1 to 5}{
| i= i + 1
| print(i)
| }
<console>:13: error: reassignment to val
i= i + 1
^