Scala: map vs flatMap

Reading Time: 3 minutes

While working with collections in Scala we frequently find ourselves using two most popular Functional combinators i.e, map() and its close cousin flatMap(). Both are higher-order functions. Click here to know more about higher order functions. In this blog, we will explore the the map and flatMap in detail.

map():

The map method transforms a collection by applying a function to each element of that collection.

trait Traversable[A] {
def map[B](f: A => B): Traversable[B]
.....

map is a function defined actually on a Traversable trait and is inherited by the number of collections. Infect, most of the collections in Scala have map function on them. So, in the above-defined trait if Traversable is a parameter as type by A, meaning A is the type of element that the collection contains. The map has additional parameter B because the function we are supplying transforms the source type into some kind of destination type. The collection type remains, but element type may change. For instance, if the collection contains elements of type String then our output can be a transform collection contains elements of type string or any other type.

We can also use the short notation( “_” ) in the map if we use each parameter exactly once where each underscore _ stands for one function parameter and gives the same result.

languages.map(_.toUpperCase)
languages.map(_.length)

flatMap():

The flatMap() method is similar to the map() method, but the only difference is that in flatMap, the inner grouping of an item is removed and a sequence is generated. The flatMap method acts as a shorthand to map a collection and then immediately flatten it. For Example:

We can see from the above examples, flatMap allows us to transform the underlying sequence by applying a function that goes from one element to many elements.

The flatMap is also a member of the Traversable trait which is implemented by Scala’s collection classes. The only change is the additional parameter which is Traversable[B] and not B because each collection for each element is expended into result.

trait Traversable[A] {
def flatMap[B](f: A => Traversable[B]): Traversable[B]
.....

The flatMap is way more powerful than map. We can use flatMap to generate a collection that is either larger or smaller than the original input:

Monads

The map() and flatMap() methods can be use to represents sequential computations i.e, if we process some value and require to pass intermediate results to next method, this type of structure is called Monad. Click here to know more about Monads. An example of the Monad:

val numList = List(1,2)
val strList = List("hi", "hello")

strList flatMap { x => numList map {
y => x*y
}
}

Output:
List[String] = List(hi, hihi, hello, hellohello)

Conclusion

We introduced Scala map() and flatMap() methods. Scala’s mapping capabilities are far more powerful and versatile with these two functional combinators. They are tremendously useful in writing code that concisely and elegantly follows the functional paradigm of immutability. Also, we had seen how these two methods use in Monads. In short, the effective knowledge of these two higher-order functions makes able the Scala developer to make their Scala application simple, concise, and maintainable.