3-5.【函数式编程】讨论 map、flatMap、compactMap 的使用场景和效率差异。

2 阅读2分钟

1️⃣ map

作用:对集合(数组、可选等)中的每个元素应用闭包,生成一个同样结构的新集合

  • 不会去掉 nil
  • 不会扁平化嵌套数组

适用场景

  • 纯转换操作,例如把数字转成字符串、平方、加前缀等

示例

let numbers = [1, 2, 3]
let strings = numbers.map { "Number ($0)" }
print(strings) // ["Number 1", "Number 2", "Number 3"]
  • 可选类型:
let number: Int? = 5
let doubled = number.map { $0 * 2 }
print(doubled) // Optional(10)

效率

  • 遍历整个集合,每个元素调用一次闭包
  • 不做额外过滤或扁平化,所以最轻量,效率高

2️⃣ flatMap

flatMap数组可选类型 中行为不同:

数组

  • 作用:映射数组元素并“扁平化”一层

  • 常用于:

    • 将嵌套数组变成一维数组
    • 映射后返回数组,再扁平化

示例

let nested = [[1, 2], [3, 4]]
let flattened = nested.flatMap { $0 }
print(flattened) // [1, 2, 3, 4]

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

可选类型

  • 作用:避免可选嵌套(Optional<Optional>)
  • 常用于链式可选操作
let str: String? = "123"
let number = str.flatMap { Int($0) }
print(number) // Optional(123)

效率

  • 数组 flatMap 多了一步扁平化,可能会创建新数组,比 map 略慢
  • 可选 flatMap 基本等效于 map,只是避免多层 Optional

3️⃣ compactMap

作用:类似 map,但会自动去掉返回值中的 nil

  • 适合可选类型或可能返回 nil 的映射
  • 相比 map + filter { $0 != nil } 更简洁

示例

let strings = ["1", "two", "3", "four"]
let numbers = strings.compactMap { Int($0) }
print(numbers) // [1, 3]
  • 可选类型示例:
let number: Int? = nil
let doubled = number.compactMap { $0 * 2 }
print(doubled) // []

效率

  • 遍历集合并在同一步去掉 nil
  • map + filter 高效,因为只遍历一次

4️⃣ 使用场景总结

方法返回类型去 nil扁平化场景
map同类型集合普通转换,保留结构
flatMap (数组)扁平化数组嵌套数组扁平化,映射后数组
flatMap (Optional)Optional❌(自动解 Optional)链式可选操作,避免 Optional
compactMap同类型集合(去掉 nil)映射可能返回 nil 的值,自动过滤 nil

5️⃣ 效率对比总结

  • map 最轻量,直接遍历,不做额外操作
  • compactMap 遍历一次,顺便过滤 nil,比 map + filter
  • flatMap(数组)需要额外扁平化操作,比 map/compactMap 稍慢
  • flatMap(Optional)效率与 map 接近

💡 经验法则

  1. 想保留元素结构 → 用 map
  2. 想去掉 nil → 用 compactMap
  3. 想扁平化嵌套数组 → 用数组 flatMap
  4. 链式可选处理 → 用可选 flatMap