In a previous Scala Saturday post, we looked at the
map method. As a quick review,
map lets you take a collection of elements, calculate a new value from each source element, and create a new collection containing those new values. The mapping function has the following signature:
A => B
In other words, the function takes a single value of type
A and returns a single value of type
But what if you have a mapping function with this signature?
A => List[B]
In other words, this function does not take one value and produce one value. Rather it takes one value and produces multiple values. What if you’re OK with that, but you just need to take those many values returned from each mapping and smash them all together into one list?
From Side to Side
Most of the guys in legendary progressive rock band Yes didn’t have just one job on their Close to the Edge album. They performed multiple duties. So let’s create a
Musician case class to represent a musician and the list of instruments he plays on the album:
case class Musician( name: String, instruments: List[String])
Now you can create a list of musicians:
val yes = List( Musician("Jon Anderson", List("vocals")), Musician( "Steve Howe", List("electric guitars", "acoustic guitars", "vocals") ), Musician( "Chris Squire", List("bass guitar", "acoustic guitars", "vocals") ), Musician( "Rick Wakeman", List("Hammond organ", "Minimoog", "Mellotron", "grand piano", "RMI 368 Electra-Piano and Harpsichord", "pipe organ at St. Giles, Cripplegate church") ), Musician( "Bill Bruford", List("drums", "percussion") ) )
Maybe you want one long list of every instrument the fellows in Yes used on the album. You just have to map each musician to his list of instruments, and then concatenate those lists together:
val instruments = yes.map(_.instruments).flatten // instruments: List[String] = // List(vocals, electric guitars, acoustic guitars, // vocals, bass guitar, ...)
The Total Mass
What if there were a function that could do both of those things—perform the transformation and the concatenation all in one? Turns out that there is:
val instruments = yes flatMap (_.instruments) // instruments: List[String] = // List(vocals, electric guitars, acoustic guitars, // vocals, bass guitar, ...)
How ’bout that? The very same results all in one function!
flatMap performs a map and a flatten all in one function call.
flatMap examples here only in terms of lists, but the Scala’s other collections define the
flatMap method, too: