A collection of Scala ‘flatMap’ examples

Scala flatMap FAQ: Can you share some Scala flatMap examples?

Sure. When I was first trying to learn Scala, and cram the collections' flatMap method into my brain, I scoured books and the internet for great flatMap examples. Once I had a little grasp of it I started creating my own examples, and tried to keep them simple. I share those examples in this tutorial.



Back to top

Using flatMap on a list of Strings

To get started, the following examples show the differences between map and flatMap on a Seq[String]:

scala> val fruits = Seq("apple", "banana", "orange")
fruits: Seq[java.lang.String] = List(apple, banana, orange)

scala> fruits.map(_.toUpperCase)
res0: Seq[java.lang.String] = List(APPLE, BANANA, ORANGE)

scala> fruits.flatMap(_.toUpperCase)
res1: Seq[Char] = List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)

Quite a difference, right? Because of the way flatMap works, it flattens the resulting list of strings into a sequence of characters (Seq[Char]). I like to think of flatMap as a combination of map followed by flatten, so it first runs map on the sequence, then runs flatten, giving the result shown.

You can see this by running map and then flatten yourself:

scala> val mapResult = fruits.map(_.toUpperCase)
mapResult: Seq[String] = List(APPLE, BANANA, ORANGE)

scala> val flattenResult = mapResult.flatten
flattenResult: Seq[Char] = List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)

Tip: I often refer to flatMap as mapFlat so I can remember how it works.

Back to top

Using a list of Options with map and flatMap

While it’s good to see how flatMap works on sequences, it really shines when it comes to working with the Option/Some/None classes (and similar classes like Try and Either).

The following examples show more differences between map and flatMap for a method that converts a String to an Int, and returns its result as an Option[Int]:

def toInt(s: String): Option[Int] = {
    try {
    } catch {
        // catch Exception to catch null 's'
        case e: Exception => None

Here are a few examples to show how map and flatMap work on a simple list of strings that you want to convert to Int:

scala> val strings = Seq("1", "2", "foo", "3", "bar")
strings: Seq[java.lang.String] = List(1, 2, foo, 3, bar)

scala> strings.map(toInt)
res0: Seq[Option[Int]] = List(Some(1), Some(2), None, Some(3), None)

scala> strings.flatMap(toInt)
res1: Seq[Int] = List(1, 2, 3)

scala> strings.flatMap(toInt).sum
res2: Int = 6

flatMap does a nice job of flattening a list that has Some and None values in it.

Once again it’s worth noting that flatMap is equivalent to running map and then flatten:

scala> val mapResult = strings.map(toInt)
mapResult: Seq[Option[Int]] = List(Some(1), Some(2), None, Some(3), None)

scala> val flattenResult = mapResult.flatten
flattenResult: Seq[Int] = List(1, 2, 3)
Back to top

flatMap with another function

The following code is not mine (see the URL below), but it does a great job of demonstrating flatMap when given the simple method g, where g returns three Int values when given one Int as input. That is, it transforms the single Int to the three resulting Ints:

scala> val list = List(1,2,3,4,5)
list: List[Int] = List(1, 2, 3, 4, 5)

scala> def g(v:Int) = List(v-1, v, v+1)
g: (v: Int)List[Int]

scala> list.map(x => g(x))
res0: List[List[Int]] = List(List(0, 1, 2), List(1, 2, 3), List(2, 3, 4), List(3, 4, 5), List(4, 5, 6))

scala> list.flatMap(x => g(x))
res1: List[Int] = List(0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6)

This great example comes from the following URL:

See that page for more map and flatMap examples.

Back to top

Convert Map values to a sequence with flatMap

Here's an interesting use of flatMap I just thought about. Although there are other ways to get the values from a Scala map, you can use flatMap for this purpose:

scala> val map = Map(1 -> "one", 2 -> "two", 3 -> "three")
map: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> one, 2 -> two, 3 -> three)

scala> 1 to map.size flatMap(map.get)
res0: scala.collection.immutable.IndexedSeq[java.lang.String] = Vector(one, two, three)

By contrast, notice what the map method gives you:

scala> 1 to map.size map(map.get)
res1: scala.collection.immutable.IndexedSeq[Option[java.lang.String]] = Vector(Some(one), Some(two), Some(three))

If you're new to Scala, note that the flatMap example is the same as this line of code, which may be more understandable:

1 to map.size flatMap(map.get(_))

Again, probably not ideal, but I'm just trying to throw different ideas out here.

Back to top

flatMap examples from Twitter documentation

The folks at Twitter have put out some excellent Scala documentation, including a collection of flatMap examples that I've found in two different documents.

This first example invokes flatMap twice on a sequence of characters:

val chars = 'a' to 'z'
val perms = chars flatMap { a => 
  chars flatMap { b => 
    if (a != b) Seq("%c%c".format(a, b)) 
    else Seq() 

Can you guess what perms looks like? Here is some of it:

perms: scala.collection.immutable.IndexedSeq[String] = Vector(ab, ac, ad, ae, af, ag, ah, ai, aj ...

// goes on until ... zw, zx, zy

They also show the following example of flatMap with Option. Remember that an Option is a container of 0 or 1 things, then guess what this code does:

val host: Option[String] = ..
val port: Option[Int] = ..

val addr: Option[InetSocketAddress] =
  host flatMap { h =>
    port map { p =>
      new InetSocketAddress(h, p)

Those two examples came from Twitter's Effective Scala document, which is an excellent doc.

This morning (Nov. 2, 2012), I saw the following additional flatMap examples in a new presentation by Marius:

Seq(1,2,3,4) flatMap { x =>
  Seq(x, -x)

// results in:
res0: Seq[Int] = List(1, -1, 2, -2, 3, -3, 4, -4)

Again this might be easier to understand if you look at map and then flatten:

scala> Seq(1,2,3,4) map { x =>
     |   Seq(x, -x)
     | }
res1: Seq[Seq[Int]] = List(List(1, -1), List(2, -2), List(3, -3), List(4, -4))

scala> res1.flatten
res2: Seq[Int] = List(1, -1, 2, -2, 3, -3, 4, -4)

Here's the second example from that presentation:

Seq(1,2,3,4) flatMap { x =>
  if (x%2 == 0) Seq(x)
  else Seq()

// results in:
res1: Seq[Int] = List(2, 4)
Back to top

flatMap in the Play Framework

Here’s an example of flatMap being used in a Play Framework method:

flatMap example in the Play Framework

That example comes from this page. If you look at that page, you’ll see that the other examples use map, but this particular example uses flatMap. It’s an interesting exercise to look at those examples and wonder why this is.

Back to top

Using flatMap with Option and other monads

As I’ve learned over time, in the functional programming world, flatMap is used to work with monads — Scala data types that implement map and flatMap — such as Option, List, Future, etc. Here are a few examples where I demonstrate that:

If you’re interested in a concise example, here’s some code from the second link. First, create some nested Options:

val o1 = Option(1)
val oo1 = Option(o1)
val ooo1 = Option(oo1)

Next, here’s how to use flatMap with those nested Options:

ooo1 flatMap { oo1 =>
    oo1 flatMap { o1 =>

The last link shows that this for-expression:

val x = for {
    i <- Option(3)
    j <- Option(4)
} yield i * j

is equivalent to this use of flatMap and map:

val x = Option(3) flatMap { i =>
    Option(4) map { j =>
        i * j

For more details, please see those two links. (The first link probably provides a better all-around example.)

Back to top

Scala flatmap examples - Summary

I hope it helps to show some Scala flatMap examples, without too much discussion for the moment. In the end, flatMap is just a combination of map and flatten, so if map leaves you with a list of lists (or strings), add flatten to it. If that gives you what you need, call flatMap instead of map and flatten. After a while your brain will naturally think "flat map" without needing those intermediate steps.

If you have any flatMap examples you want to share, or improvements to the code shown, just leave a note in the Comments section.

Also, here's a repeat of those earlier links:

Back to top

Add new comment

The content of this field is kept private and will not be shown publicly.

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.
By submitting this form, you accept the Mollom privacy policy.