Swift中flatMap和compactMap的区别

Bil*_*fas 21 swift swift4 swift4.1

似乎在Swift 4.1 flatMap中已弃用.然而,Swift 4.1中 有一个新方法,compactMap它做同样的事情?有了flatMap你可以集合中变换的每个对象,然后删除在无任何项目.
像flatMap一样

let array = ["1", "2", nil] 
array.flatMap { $0 } // will return "1", "2"
Run Code Online (Sandbox Code Playgroud)

就像compactMap一样

let array = ["1", "2", nil] 
array.compactMap { $0 } // will return "1", "2"
Run Code Online (Sandbox Code Playgroud)

compactMap 正在做同样的事情.

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

Meh*_*hdi 21

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

Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element]  
Optional.flatMap<U>(_: (Wrapped) -> U?) -> U?  
Sequence.flatMap<U>(_: (Element) -> U?) -> [U]  
Run Code Online (Sandbox Code Playgroud)

最后一个重载函数可能会以两种方式被滥用:
请考虑以下结构和数组:

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")]  
Run Code Online (Sandbox Code Playgroud)

第一种方式:额外的包装和展开:
如果您需要获得阵列中包含的people一系列人员,您可以使用两个功能:

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

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

第二种方式 - 字符串与集合协议的一致性:
认为你需要从people数组中获取人名的列表.您可以使用以下行:

let names = people.flatMap({$0.name})  
Run Code Online (Sandbox Code Playgroud)

如果您使用4.0之前的swift版本,您将获得转换后的列表

["Osame", "Masoud", "Mehdi"]  
Run Code Online (Sandbox Code Playgroud)

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

["O", "s", "a", "m", "e", "M", "a", "s", "o", "u", "d", "M", "e", "h", "d", "i"]
Run Code Online (Sandbox Code Playgroud)

结论:他们弃用了flatMap的第三个重载()
由于这些误用,swift团队决定弃用flatMap函数的第三个重载.他们对你需要处理Optionals 的情况的解决方案是引入一个新的函数compactMap(),它会给你预期的结果.


Bil*_*lal 19

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

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

详情请见此处.

  • @Krin-San你错过了这一点.flatMap有三种不同的变体.接受*可选值*仅限于已弃用.因此,您使用的示例flatMap是不同的方法,不会弃用.将你的分数改为这个'让分数:[[国际空间]?] = [[5,2,7],[4,8],[9,1,3]]`你会看到被弃用的警告以及与使用'compactMap'相同的结果. (2认同)