map vs flatMap vs comcatMap

426 阅读2分钟

加深理解代替单纯记忆

map相关方法有哪些

  • map
  • flatMap
  • compactMap

哪些地方中有这些方法

  1. Sequence protocol
  2. Optional(没有compactMap方法)

Sequence

  • 常见的数据结构有,Array、Dictionary、Set等都遵循该协议

方法声明

  • func map<T>(_ transform: (Self.Element) throws -> T) rethrows -> [T]

  • func flatMap<SegmentOfResult>(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence

  • func compactMap<ElementOfResult>(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

  • func flatMap<ElementOfResult>(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

    • 从Swift 4.1开始,该方法由于不好用,已被废弃

map方法

  • 之所以叫做map,核心的工作就是做映射
  • 将sequence中的每个元素,通过closure的处理一对一的映射到一个新序列
  • 因为是泛型方法,需要指定映射后数组元素的类型
  • 也就是说,map后的sequence和原sequence的元素数是相等的
let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let lowercaseNames = cast.map { $0.lowercased() }
// 'lowercaseNames' == ["vivien", "marlon", "kim", "karl"]
let letterCounts = cast.map { $0.count }
// 'letterCounts' == [6, 6, 3, 4]

flatMap方法

  • 核心工作仍然是通过closure进行映射
  • 通过声明可知,closure的返回值也要是一个Sequence
    • 这适用于对原序列的每个元素,每次映射要映射出一个新序列的情况
  • 仔细观察方法的返回结果[SegmentOfResult.Element],并不是我们想当然的[SegmentOfResult],这就是flat的作用
  • flat是该方法的特点--平铺,即将返回的序列进行展开操作
let numbers = [1, 2, 3, 4]

let mapped = numbers.map { Array(repeating: $0, count: $0) }
// [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]

let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }
// [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

compactMap方法

  • 核心工作也是通过closure进行映射
  • 与map的不同就在于compact一词(简洁的意思),返回结果的数组中被精简了
    • 所有optional的值会自动解包
    • 所有nil的值会被干掉
    • 所以结果可能和原序列元素数不同
let possibleNumbers = ["1", "2", "three", "///4///", "5"]

let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
// [1, 2, nil, nil, 5]

let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
// [1, 2, 5]

不再使用的flatMap方法

  • 废弃的flatMap方法在closure完成时进行一次wrap,最后又会进行一次解包,浪费资源
  • 因为有另一个同名的方法,在使用上容易产生歧义
  • 引入compactMap来代替该方法

Optional

注意Optional中仅有mapflatMap方法,没有compactMap

方法声明

需要说明一点,下面方法transform参数中的Wrapped类型,是Optional的泛型类型,也就是说传给transform的参数是经过解包的、实际上表示的内容,比如Int?,那此处Wrapped表示的就是Int

  • func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U?
  • func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?

总结

  • 两个map方法都是将optional解包后传递给transform,transform结束后,结果作为方法的返回值
  • 两个方法都返回optional的值
  • 当optional是nil的时候,两个方法都会返回nil
  • 不同点在于flatMap的transform允许返回optional值

参考