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
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]
似乎在 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
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]