The unexpected but convenience case of flatMap in Swift
Yesterday night I found myself reading this code in GitHub
for dictionary in array {
- if let interaction = Interaction(dictionary: dictionary) {
- interactions.append(interaction)
- }
- }
+ interactions = array.flatMap { Interaction(dictionary: $0) }
I read the diff a couple of times but I couldn’t understand why flatMap
was used to replace the original code. I said to myself that was too late to understand it and fell asleep.
But today I’ve seen the tab on Safari still opened and I decided to open a Playground to check what was going on, and finally I understood my confusion.
As I understand flatMap
should just apply a function to the elements of the collection and flatten the result.
To give an example: Given a list of strings with multiple words:
["hello world", "bye bye world"]
And the function that separates a string into a list of words. If you use map
you will receive a list of lists of strings.
[["hello", "world"], ["bye", "bye", "world"]]
You can then flatten
that list one level to receive just a list of words:
["hello", "world", "bye", "bye", "world"]
flatMap
is just the combination of those two functions.
If instead of a function that returns and Array, you map
a function that returns an Optional you will receive and array of Optionals.
func maybeAString(param: String) -> String? {
guard param.characters.count > 2 else { return nil }
return param
}
["this will pass", "no"].map(maybeAString)
// [{Some "this will pass"}, None]
Applying flatMap
I was expecting to receive and array of the actual values and nils. But in Swift flatMap
actually gets rid of the nil.
["this will pass", "no"].flatMap(maybeAString)
// ["this will pass"]
It’s kind of combining map (to apply the function), flatten (to unwrap the optionals) and filter (to remove the nils). Maybe I’m completely wrong but in any case I think it’s a nice feature that we can ignore the nils after applying flatMap
.