Swift 中 flatMap 和 compactMap 的区别

Difference between flatMap and compactMap in Swift

似乎在 Swift 4.1 flatMap 中已弃用。但是 Swift 4.1 compactMap 中有一个新方法在做同样的事情? 使用 flatMap 您可以转换集合中的每个对象,然后删除所有为零的项目。
喜欢flatMap

let array = ["1", "2", nil] 
array.flatMap { [=11=] } // will return "1", "2"

喜欢 compactMap

let array = ["1", "2", nil] 
array.compactMap { [=12=] } // will return "1", "2"

compactMap 也在做同样的事情。

这两种方法有什么区别?为什么 Apple 决定重命名该方法?

flatMap 有三种不同的变体。 Sequence.flatMap(_:) 接受返回可选值的闭包的变体已被弃用。 Sequence 和 Optional 上 flatMap(_:) 的其他变体保持原样。提案文件中解释的原因是由于滥用。

已弃用 flatMap 变体功能在新方法下完全相同 compactMap

查看详情here

Swift 标准库为 flatMap 函数定义了 3 个重载:

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

最后一个重载函数可能有两种误用:
考虑以下结构和数组:

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")
]

第一种方式:附加包装和展开:
如果您需要获取包含在 people 数组中的一组人的年龄,您可以使用两个函数:

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

在这种情况下,map 函数将完成工作,无需使用 flatMap,因为两者产生相同的结果。此外,在 flatMap 的这个用例中有一个无用的包装和解包过程。(闭包参数用 Optional 包装它的返回值,而 flatMap 的实现在返回之前解包 Optional 值)

第二种方式 - 字符串符合收集协议:
认为您需要从 people 数组中获取人员姓名列表。您可以使用以下行:

let names = people.flatMap({[=13=].name})  

如果您使用的是 4.0 之前的 swift 版本,您将获得

的转换列表
["Osame", "Masoud", "Mehdi"]  

但在较新的版本中 String 符合 Collection 协议,因此,您对 flatMap() 的使用将匹配第一个重载函数而不是第三个重载函数,并且会给您一个扁平的转换值的结果:

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

结论:他们弃用了 flatMap() 的第三次重载
由于这些误用,swift 团队决定弃用 flatMap 函数的第三个重载。到目前为止,他们对需要处理 Optional 的情况的解决方案是引入一个名为 compactMap() 的新函数,它将为您提供预期的结果。

High-order 函数 - 是一个函数,它由返回参数 or/and 中的另一个函数操作。例如 - 排序、映射、过滤、缩减...

map vs compactMap vs flatMap

[RxJava Map vs FlatMap]

  • map - 转换(可选,序列,字符串)
  • compactMap - 删除 nil(Array)
  • flatMap - 将困难的结构扁平化为一个(可选,Collection)

flatMap 对比 compactMap

在 Swift v4.1 之前,flatMap 的三个实现有一席之地(没有 compactMap)。该实现负责从序列中删除 nil 。 map 而不是 flatMap

实验

//---------------------------------------
//map - for Optional, Sequence, String, Combine
//transform

//Optional
let mapOptional1: Int? = Optional(1).map { [=10=] } //Optional(1)
let mapOptional2: Int? = Optional(nil).map { [=10=] } //nil
let mapOptional3: Int?? = Optional(1).map { _ in nil } //Optional(nil)
let mapOptional4: Int?? = Optional(1).map { _ in Optional(nil) } //Optional(nil)

//collection
let mapCollection1: [Int] = [1, 2].map { [=10=] } //[1, 2]
let mapCollection2: [Int?] = [1, 2, nil, 4].map { [=10=] } //Optional(1), Optional(2), nil, Optional(4),
let mapCollection3: [Int?] = ["Hello", "1"].map { Int([=10=]) } //[nil, Optional(1)]

//String
let mapString1: [Character] = "Alex".map { [=10=] } //["A", "l", "e", "x"]




//---------------------------------------
//compactMap(one of flatMap before 4.1) - Array, Combine
//removes nil from the input array

//Collection
let compactMapCollection1: [Int] = [1, 2, nil, 4].compactMap { [=10=] } //[1, 2, 4]
let compactMapCollection2: [[Int]] = [[1, 2], nil, [3, 4]].compactMap { [=10=] } //[[1, 2], [3, 4]]




//---------------------------------------
//flatMap - Optional, Collection, Combime

//Optional
let flatMapOptional1: Int? = Optional(1).flatMap { [=10=] } //Optional(1)
let flatMapOptional2: Int? = Optional(nil).flatMap { [=10=] } //nil
let flatMapOptional3: Int? = Optional(1).flatMap { _ in nil }
let flatMapOptional4: Int? = Optional(1).flatMap { _ in Optional(nil) }

//Collection
let flatMapCollection1: [Int] = [[1, 2], [3, 4]].flatMap { [=10=] } //[1, 2, 3, 4]
let flatMapCollection2: [[Int]] = [[1, 2], nil, [3, 4]].flatMap { [=10=] } //DEPRECATED(use compactMap): [[1, 2], [3, 4]]
let flatMapCollection3: [Int?] = [[1, nil, 2], [3, 4]].flatMap { [=10=] } //[Optional(1), nil, Optional(2), Optional(3), Optional(4)]
let flatMapCollection4: [Int] = [1, 2].flatMap { [=10=] } //DEPRECATED(use compactMap):[1, 2]

[Swift Optional map vs flatMap]
[Swift Functor, Applicative, Monad]