I’ve come across the flatMap
function several times. I’ve used map
many times, but didn’t understand why there was a need for flatMap
? The function’s description is quite concise and doesn’t explain much (transform
is the only closure parameter that this function accepts):
Return an Array containing the concatenated results of mapping transform over self.
“Flat” Array Link to heading
The simplest and most obvious application of flatMap
is to reduce the dimensionality of an array:
let array = [[0, 1, 2], [3, 4, 5]]
let flatArray = array.flatMap { $0 } // [0, 1, 2, 3, 4, 5]
Here we don’t change the array’s values. What if we need to get values ten times larger? The first implementation that comes to mind doesn’t work:
let flatArray10 = array.flatMap { $0 * 10 }
The issue is that the argument in the closure taken by flatMap is not a number but an array, i.e., [0, 1, 2]
, [3, 4, 5]
. Therefore, you can get an array of numbers multiplied by 10 in this way:
let flatArray10 = array.flatMap { $0.map { $0 * 10 } }
Optional Link to heading
This function can work not only with arrays but also with optionals. For example, there is an array of numbers in string representation. This can be obtained, for example, in JSON, where numbers were placed in strings. You need to get an array of numbers so that you can work with them as with numbers, not strings. Int
has init?()
that takes a string and returns a number. The only problem is that it creates Int?
, which is not very convenient. This is where flatMap
can help. As an example, one of the strings is not a number, and its conversion result to Int
will be nil
:
let arrayOfStrings = ["0", "1", "a", "2"]
let arrayOfInts = arrayOfStrings.flatMap { Int($0) }
arrayOfInts // [0, 1, 2]
Another good example of such a technique can be creating an array [UIImage]
from string image names [String]
:
arrayOfImageNames.flatMap { UIImage(named: $0) }
You can also apply flatMap
directly to an optional. For example, creating a URL from a string, which is of type String?
. It can’t be passed directly. And here flatMap
comes to the rescue:
let urlString: String? = "http://apple.com"
let url: URL? = urlString.flatMap { URL(string: $0) }