5月27日 11:30

Swift 高阶函数 map、filter、reduce 怎么用?有什么区别?

高阶函数是"接受函数作为参数"或"返回函数"的函数。Swift 里最常用的是 map、filter、reduce,加上 compactMap、flatMap、sorted。它们让集合操作从命令式循环变成声明式一行代码。

  • map:变换每个元素,返回新数组
  • filter:按条件筛选,返回满足条件的元素
  • reduce:把所有元素聚合成一个值
  • compactMap:map + 过滤 nil
  • flatMap:map + 展平一层嵌套

追问

map 和 compactMap 有什么区别?

map 对每个元素做变换,结果包含 nil(如果闭包返回 Optional)。compactMap 会自动过滤掉 nil,只保留非空值。典型场景:字符串数组转 Int——["1", "abc", "3"].compactMap { Int($0) } 得到 [1, 3],用 map 则得到 [Optional(1), nil, Optional(3)]。规则:闭包返回 Optional 时用 compactMap,否则用 map。

flatMap 和 compactMap 有什么区别?

Swift 4.1 之后,flatMap 的职责简化了:只用来展平嵌套数组([[1,2],[3,4]].flatMap { $0 } 得到 [1,2,3,4])。过滤 nil 的功能全部交给 compactMap。之前 flatMap 两个功能都有,容易混淆,所以拆开了。现在记住:去 nil 用 compactMap,展平用 flatMap。

reduce 能做什么 map 和 filter 做不到的事?

reduce 把集合聚合成任意类型的单个值——字符串拼接、字典构建、对象累积修改都能做。map 和 filter 只能返回数组。比如统计字符频率:str.reduce(into: [:]) { $0[$1, default: 0] += 1 },这个 map 做不了。另一个例子:把数组转成字典 items.reduce(into: [:]) { $0[$1.id] = $1 }

链式调用 map + filter + reduce 性能怎么样?

每次链式调用都创建一个中间数组——map 创建一个,filter 再创建一个。数据量大时这有额外内存和 CPU 开销。如果性能敏感,用 reduce 合并操作,或者用 for 循环一次遍历完成。但大部分场景下,链式调用的可读性收益远大于性能损耗——除非 profile 发现有问题,否则别过早优化。

forEach 和 for-in 有什么区别?

forEach 不支持 break/continue/return——闭包里的 return 只退出当前闭包,不影响外层。for-in 循环可以用 break 提前退出。所以 forEach 只适合"对每个元素执行操作且必须全部执行"的场景。需要条件退出时用 for-in。另外 forEach 不返回值,不能链式调用。

写段代码

swift
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // map: 变换 let doubled = numbers.map { $0 * 2 } // filter: 筛选 let evens = numbers.filter { $0 % 2 == 0 } // reduce: 聚合 let sum = numbers.reduce(0, +) // compactMap: 去 nil let strings = ["1", "abc", "3"] let ints = strings.compactMap { Int($0) } // [1, 3] // flatMap: 展平 let nested = [[1, 2], [3, 4]] let flat = nested.flatMap { $0 } // [1, 2, 3, 4] // 链式:筛选 + 变换 + 聚合 let result = numbers .filter { $0 % 2 == 0 } .map { $0 * $0 } .reduce(0, +) // 4+16+36+64+100 = 220 // reduce(into:): 构建字典 let freq = "hello".reduce(into: [Character: Int]()) { $0[$1, default: 0] += 1 }
标签:Swift