Scala Foundation Course - Higher Order Controls in Collections


Welcome back. In the earlier video, I talked about the basic idea behind Higher Order Control abstraction. In this video, I will talk about the four fundamental control abstractions that Scala implements for almost every collection type.
Here is the list of those abstractions.

  1. foreach
  2. map
  3. flatMap
  4. filter and withFilter

All these methods are same in one respect. They take a function as an argument and apply the function to each element in the collection. So, all of them are a kind of specialized loop constructs.
But they are not same. Each one serves a different purpose. Let's try to understand the specifics of these methods using a List collection.

Scala foreach

The foreach is the simplest one. It takes one function as an argument and applies the function to each element of the collection. That's why it has got the name as foreach.
It's purely a loop. But the most important feature is that it doesn't return anything. The return type of the foreach method is a Unit. Here is a primary example.

                                
    val l = List("india", "USA", "UK", "china", "russia")
    def f1(s: String) = {
        println("Printing " + s)
        "Returning " + s
    }                                       
                         

I have a list, and I have a function f1. I call the foreach on the list and pass the function f1. It returns nothing. My function f1 does return a value, but foreach is designed to discard that value.
While working with Scala collections, we use the foreach for a side effect. I mean, if you have a function that has a side effect and you want to apply it to all elements of a collection, use the foreach method. The most common example is the println.

                                
    l.foreach(println)
    /*Output
    india
    USA
    UK
    china
    Russia
    */                                          
                         

Scala map

The next one is the map method. The map method is the most commonly used method. Like foreach, this one is also a loop. It takes a function and applies the function to each element. But unlike foreach, the map method returns a value.
Let's apply the function f1 on each element of my list.

                                
    l.map(f1)
    /*Output
    Printing india
    Printing USA
    Printing UK
    Printing china
    Printing russia
    res7: List[String] = List(Returning india, Returning USA, Returning UK, Returning china, Returning russia)
    */                                          
                         

What do you see? It executes the function f1 for each element of the list, and hence we get those outputs. But it also returns a list of strings. So, the map method takes a function and applies it to all elements, collects the result of the function and returns a new collection. So, the return type of the map method is a collection of the return type of f1.
The most common use of the map method is to transform a collection into a new collection by applying some transformation logic to each element of the existing collection.

Scala flatMap

The next one is the flatMap. The flat map is a specialized version of the map method. You can't understand it without an example. So, let's take an example.

                                
    def f3(s:String) = s.split(" ")                                          
                         

We have a function there. It takes a string and breaks it into words. The return type of the function f3 is an array of strings. Let's make a list of two strings.

                                
    val l = List("India is a mulyiparty democratic country, USA is two-party democratic country")           
                         

Now, we will apply the map method on this list.

                                
    l.map(f3)
    /*output
    res8: List[Array[String]] = List(Array(India, is, a, mulyiparty, democratic, country,, USA, is, two-party, democratic, country))
    */                                      
                         

What do you see? A List of an array. That is what I expected because map method returns a collection of the return type of f3. The return type of f3 is an array, so we get a List of an Array.
Now, let's try the flat map.

                                
    l.flatMap(f3)
    /*output
    res9: List[String] = List(India, is, a, mulyiparty, democratic, country,, USA, is, two-party, democratic, country)
    */                                      
                         

Do you see the difference? The flatMap goes one step further. It takes the return value of f3 and breaks them once again. So ultimately you get a flattened list. The flat map method has flattened the array into strings. So, if you are using map method and getting a collection of an array but you wanted a flat output, I mean break the array further into elements, use the flat map instead of map method.
You must be careful while using the flat map because, if the output of f3 is not a collection, you may get unexpected results.

Scala filter and withFilter

The final item is the filter. The filter method is simple. Like other methods that we just discussed, the filter takes a Boolean function, applies it to all elements and returns only those elements that qualify the Boolean condition. Here is a very basic example.

                                
    val l = List("india", "USA", "UK", "china", "russia")
    l.withFilter( x =>x.startsWith("i")).map(x =>x.capitalize)
    res10: List[String] = List(India)                                           
                         

The most common use of the filter method is to filter out some elements from an existing collection and create a new collection.
The withFilter is also same as the filter. There is a small difference.
The filter method returns a new collection, but withFilter doesn't return you a new collection. It will apply the Boolean function just before the subsequent method calls. Let me show you an example.

                                
    l.filter( x =>x.startsWith("i")).map(x =>x.capitalize)                                           
                         

In this example, the Boolean function applies to each element just before it applies the map method to that specific element. If the Boolean function returns true, then the element goes to the map method otherwise Scala will filter that out and it doesn't go to the map method.
In fact, if you apply filter method instead of withFilter, you should get the same results. But withFilter is efficient because it's a lazy method and applies the Boolean function when we use the element for the subsequent call.
Great! We will talk about the for expression in the next video.


You will also like:


Scala Functions

Scala is a functional programming language. Functions are the building blocks in Scala.

Learning Journal

First Class Functions

Function is a first-class citizen in functional programming. What does it mean?

Learning Journal

Hadoop Security

Hadoop security implementation using Kerberos.

Learning Journal

Scala placeholder syntax

What is a scala placeholder syntax and why do we need it? Learn from experts.

Learning Journal

Spark in Google cloud

Learn How to Install Hadoop and Spark in Google Cloud in just 2 minuts.

Learning Journal