Swift中flatMap和compactMap的区别

时间:2018-03-15 03:21:26

标签: swift swift4 swift4.1

似乎已弃用 Swift 4.1 flatMap。但是 Swift 4.1 compactMap中有一种新方法可以做同样的事情吗? 使用flatMap,您可以转换集合中的每个对象,然后删除任何nil项。
与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决定重命名该方法?

2 个答案:

答案 0 :(得分:18)

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

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

详见here

答案 1 :(得分:18)

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用例内部有一个无用的包装和解包过程。(Closure参数用Optional包装其返回的值,flatMap的实现在返回Optional之前将其解包装)

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

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

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

的转换列表。
["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()的新函数,它将为您带来预期的结果。