CompactMap and flatMap, what are the differences and when do you use each? Swift 4.1 introduced this new method with the proposal 0187: Introduce Filtermap to gain more clarity in flatMap use cases.
When to use compactMap
Use this method to receive an array of nonoptional values when your transformation produces an optional value.
See the differences between a map and a compactMap in the following example:
let scores = ["1", "2", "three", "four", "5"]
let mapped: [Int?] = scores.map { str in Int(str) }
// [1, 2, nil, nil, 5] - Two nil values as "three" and "four" are strings.
let compactMapped: [Int] = scores.compactMap { str in Int(str) }
// [1, 2, 5] - The nil values for "three" and "four" are filtered out.
When to use flatMap
Use this method to receive a single-level collection when your transformation produces a sequence or collection for each element.
See the difference between a map and a flatMap in the following example:
let scoresByName = ["Henk": [0, 5, 8], "John": [2, 5, 8]]
let mapped = scoresByName.map { $0.value }
// [[0, 5, 8], [2, 5, 8]] - An array of arrays
print(mapped)
let flatMapped = scoresByName.flatMap { $0.value }
// [0, 5, 8, 2, 5, 8] - flattened to only one array
In fact, s.flatMap(transform)
is equivalent to Array(s.map(transform).joined())
.
compactMap vs flatMap
The general rule of thumb here to remind yourself for when writing code:
Used on a sequence and having a transformation returning an optional value, use
compactMap
. If not, eithermap
orflatMap
should give you the results you need.
The reason for naming it compactMap
Although some proposed to introduce filterMap as the method name, the Swift team decided to go for compactMap instead. Reading their motivations clears things up quite a lot and explains the functionality of the method as well.
“filterMap” is a name with some precedent in other programming languages, especially functional ones, but some people felt strongly that the name was misleading because, as a combined operation, it wasn’t quite a filter or a map. Of the alternatives, the one with the strongest support seemed to be “compactMap”, which builds on the precedent of “compact”, an operation from other languages (notably Ruby) which returns a copy of the input without nil values. Swift does not currently have such an operation, and in fact it is not currently possible to express it; nonetheless, the core team agrees that it would be a reasonable operation to add, and that “compactMap” is a good name for the operation.