Difference between flatMap and compactMap in Swift

swift, swift4, swift4.1

Solution

The Swift standard library defines 3 overloads for `flatMap` function:

Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element]  
Optional.flatMap<U>(_: (Wrapped) -> U?) -> U?  
Sequence.flatMap<U>(_: (Element) -> U?) -> [U]  

The last overload function can be misused in two ways: Consider the following struct and array:

struct Person {
  var age: Int
  var name: String
}  

let people = [
  Person(age: 21, name: "Osame"),
  Person(age: 17, name: "Masoud"),
  Person(age: 20, name: "Mehdi")
]

First Way: Additional Wrapping and Unwrapping: If you needed to get an array of ages of persons included in `people` array you could use two functions :

let flatMappedAges = people.flatMap({$0.age})  // prints: [21, 17, 20]
let mappedAges = people.map({$0.age})  // prints: [21, 17, 20]  

In this case the `map` function will do the job and there is no need to use `flatMap`, because both produce the same result. Besides, there is a useless wrapping and unwrapping process inside this use case of flatMap.(The closure parameter wraps its returned value with an Optional and the implementation of flatMap unwraps the Optional value before returning it)

Second Way - String conformance to Collection Protocol: Think you need to get a list of persons' name from `people` array. You could use the following line :

let names = people.flatMap({$0.name})  

If you were using a swift version prior to 4.0 you would get a transformed list of

["Osame", "Masoud", "Mehdi"]  

but in newer versions `String` conforms to `Collection` protocol, So, your usage of `flatMap()` would match the first overload function instead of the third one and would give you a flattened result of your transformed values:

["O", "s", "a", "m", "e", "M", "a", "s", "o", "u", "d", "M", "e", "h", "d", "i"]

So, How did they solve it? They deprecated third overload of flatMap() Because of these misuses, swift team has decided to deprecate the third overload to flatMap function. And their solution to the case where you need to to deal with `Optional`s so far was to introduce a new function called `compactMap()` which will give you the expected result.

Problem

It seems like in Swift 4.1 `flatMap` is deprecated. However there is a new method in Swift 4.1 `compactMap` which is doing the same thing? With `flatMap` you can transform each object in a collection, then remove any items that were nil. Like flatMap ``` let array = ["1", "2", nil] array.flatMap { $0 } // will return "1", "2" ``` Like compactMap ``` let array = ["1", "2", nil] array.compactMap { $0 } // will return "1", "2" ``` `compactMap` is doing the same thing. What are the differences between these 2 methods? Why did Apple decide to rename the method?

Original source

Related problems