Table of Contents
- Using flatMap on a list of Strings
- Using a list of Options with map and flatMap
- flatMap with another function
- Convert Map values to a sequence with flatMap
- flatMap examples from Twitter documentation
- flatMap in the Play Framework
- Using flatMap with Option and other monads
- Summary: Scala flatmap examples
Scala flatMap
FAQ: Can you share some Scala flatMap examples with lists and other sequences?
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 how to use flatMap
with lists and sequences, I started creating my own examples, and tried to keep them simple. I share those examples in this tutorial.
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
asmapFlat
so I can remember how it works.
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 Scala 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 makeInt(s: String): Option[Int] = { try { Some(Integer.parseInt(s.trim)) } catch { 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(makeInt) res0: Seq[Option[Int]] = List(Some(1), Some(2), None, Some(3), None) scala> strings.flatMap(makeInt) res1: Seq[Int] = List(1, 2, 3) scala> strings.flatMap(makeInt).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(makeInt) 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)
Here’s some complete source code if you want to play with this example some more in a Scala REPL:
import scala.util.control.Exception.allCatch def makeInt(s: String): Option[Int] = allCatch.opt(s.toInt) val strings = List("1", "hi", "3") val ints: List[Int] = strings.flatMap(s => makeInt(s)) println(ints) // List(1, 3)
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 Int
s:
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.
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.
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)
flatMap in the Play Framework
Here’s an example of flatMap
being used in a Play Framework method:
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.
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:
- Handling nested Options with flatMap and for-expressions
- Another Scala nested option flatMap and for example
- Notes on Scala for-expressions, flatMap, and map
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 => 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.)
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
Summary: Scala flatmap examples
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: