30

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

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

像 compactMap

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

compactMap正在做同样的事情。

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

4

3 回答 3

28

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({$0.age})  // prints: [21, 17, 20]
let mappedAges = people.map({$0.age})  // prints: [21, 17, 20]  

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

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

let names = people.flatMap({$0.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到目前为止,他们对您需要处理 s 的情况的解决方案是引入一个名为的新函数compactMap(),该函数将为您提供预期的结果。

于 2018-09-17T12:38:23.603 回答
20

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

不推荐使用flatMap的变体功能在新方法下完全相同compactMap

在此处查看详细信息。

于 2018-03-15T03:47:32.173 回答
0

高阶函数- 是由另一个函数在参数中操作或/并返回的函数。例如 - 排序、映射、过滤、减少......

map vs compactMap vs flatMap

[RxJava Map vs FlatMap]

  • map- 变换(可选,序列,字符串)
  • compactMap- 删除 nil(Array)
  • flatMap- 扁平的困难结构成一个单一的(可选,收藏)

flatMap对比compactMap

在 Swift v4.1 之前,有三个实现flatMap存在(没有compactMap)。这种认识负责从序列中删除 nil。它map不仅仅是关于flatMap

实验

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

//Optional
let mapOptional1: Int? = Optional(1).map { $0 } //Optional(1)
let mapOptional2: Int? = Optional(nil).map { $0 } //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 { $0 } //[1, 2]
let mapCollection2: [Int?] = [1, 2, nil, 4].map { $0 } //Optional(1), Optional(2), nil, Optional(4),
let mapCollection3: [Int?] = ["Hello", "1"].map { Int($0) } //[nil, Optional(1)]

//String
let mapString1: [Character] = "Alex".map { $0 } //["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 { $0 } //[1, 2, 4]
let compactMapCollection2: [[Int]] = [[1, 2], nil, [3, 4]].compactMap { $0 } //[[1, 2], [3, 4]]

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

//Optional
let flatMapOptional1: Int? = Optional(1).flatMap { $0 } //Optional(1)
let flatMapOptional2: Int? = Optional(nil).flatMap { $0 } //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 { $0 } //[1, 2, 3, 4]
let flatMapCollection2: [[Int]] = [[1, 2], nil, [3, 4]].flatMap { $0 } //DEPRECATED(use compactMap): [[1, 2], [3, 4]]
let flatMapCollection3: [Int?] = [[1, nil, 2], [3, 4]].flatMap { $0 } //[Optional(1), nil, Optional(2), Optional(3), Optional(4)]
let flatMapCollection4: [Int] = [1, 2].flatMap { $0 } //DEPRECATED(use compactMap):[1, 2]

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

于 2021-11-06T19:24:55.740 回答