Sunday, 31 December 2017

Introduction to Scala - XVII

We continue the journey on Scala on the topic of  for comprehensions in this post. For all the work in this post, we will use Read-Evaluate-Print-Loop Scala interpreter. Some familiarity with Java will be of great help in understanding Scala.

For comprehensions in Scala are an enhancement over the conventional for loops in other languages. We have already seen three forms of for loop in this post. In the last few posts, we have covered many members of Collections. So, let us look at a simple for loop as shown below:

val Map1: Map[String,Int] = Map("King" -> 24000, "Kochhar" -> 17000, "De Haan" -> 17000, ("Hunold", 9000), ("Ernst", 6000), ("Austin", 4800))

var Map0: Map[String,Int] = Map()
for (m <- Map1) {
  if (m._1.head == 'K') {
    Map0 += ((m._1,m._2))
  }
}
println(Map0)


The results are shown below:

scala> val Map1: Map[String,Int] = Map("King" -> 24000, "Kochhar" -> 17000, "De Haan" -> 17000, ("Hunold", 9000), ("Ernst", 6000), ("Austin", 4800))
Map1: Map[String,Int] = Map(King -> 24000, Ernst -> 6000, Kochhar -> 17000, De Haan -> 17000, Austin -> 4800, Hunold -> 9000)

scala> var Map0: Map[String,Int] = Map()
Map0: Map[String,Int] = Map()

scala> for (m <- Map1) {
     |   if (m._1.head == 'K') {
     |     Map0 += ((m._1,m._2))
     |   }
     | }

scala> println(Map0)
Map(King -> 24000, Kochhar -> 17000)


The above code is quite straightforward. We define Map1 for our exercise. Map0 is a map with no elements. A simple for loop that filters the elements having employee names starting with 'K'. then, this printed out. In the next program, we add the if condition to the for clause:

for (m <- Map1 if m._1.head == 'K') {
    Map0 += ((m._1,m._2))
}
println(Map0)


The results are shown below:

scala> for (m <- Map1 if m._1.head == 'K') {
     |     Map0 += ((m._1,m._2))
     | }

scala> println(Map0)
Map(King -> 24000, Kochhar -> 17000)


The for program above is an example of the for comprehension that is a combination of for and if. It consists of :

1) a generator expression : m <- Map1, that generates the value for the intended for loop

2) a guard : if m._1.head == 'K', that filters the earlier defined values from generator expression

3) a definition: Map0 += ((m._1,m._2)), that is actually the processing part of the for loop

We can also have a yield added to complete the picture as shown below:

println(for (m <- Map1 if m._1.head == 'K') yield m)

The results are shown below:

scala> println(for (m <- Map1 if m._1.head == 'K') yield m)
Map(King -> 24000, Kochhar -> 17000)


Notice that above one line yields the same result as in previous two cases. Yield can be used for further processing and returning new collections as shown below:

print(for (m <- Map1 if m._1.head == 'K') yield {
val u = m
val numPattern = "[0-9]+".r
val matchPattern_List = numPattern.findAllIn(u.toString).toVector
matchPattern_List})


The results are shown below:

scala> print(for (m <- Map1 if m._1.head == 'K') yield {
     | val u = m
     | val numPattern = "[0-9]+".r
     | val matchPattern_List = numPattern.findAllIn(u.toString).toVector
     | matchPattern_List})
List(Vector(24000), Vector(17000))


Note that apart from the processing part in yield, we have brought in regular expressions. But, that is a topic for another day.

This concludes the discussion on for comprehension in Scala