flatMap
compactMap 和 flatMap 的详细区别
虽然 compactMap 和 flatMap 在某些场景下(例如处理可选值的数组)看似相似,但它们的设计目标和行为有本质上的区别。以下从概念、语法、功能差异以及使用场景来详细说明。
1. 定义与设计目标
flatMap
- 定义:
flatMap是一个将 映射(map)和 展平(flatten)结合的操作。- 它会对数组中的每个元素应用一个闭包操作,并将返回的结果「拍平」(如果结果是嵌套的数组)。
- 设计目标:
- 用于将数组的每个元素映射到新值,同时展平嵌套的数组或去除可选值中的
nil。 - 适用于嵌套数组(如
[[1, 2], [3, 4]])的展开操作。
- 用于将数组的每个元素映射到新值,同时展平嵌套的数组或去除可选值中的
compactMap
- 定义:
compactMap是专门用于处理 可选值的数组 的操作。- 它会对数组的每个元素应用一个闭包操作,将结果中的
nil值过滤掉,最终返回一个非可选值的数组。
- 设计目标:
- 用于过滤掉映射操作结果中的
nil值。 - 不适用于嵌套数组展开。
- 用于过滤掉映射操作结果中的
2. 核心区别
| 特性 | flatMap | compactMap |
|---|---|---|
| 作用范围 | 同时支持嵌套数组展平和过滤 nil | 专注于过滤 nil |
| 嵌套数组展开 | 会展开嵌套数组 | 不会展开嵌套数组 |
处理 nil | 能过滤 nil,但设计初衷并非专注于此 | 专门用于过滤 nil 的场景 |
| 结果结构 | 单层展平后的新数组 | 非 nil 值的新数组 |
3. 行为示例
flatMap 示例
3.1 嵌套数组的展开
swift
CopyEdit
let nestedArray = [[1, 2], [3, 4], [5]] let flattenedArray = nestedArray.flatMap { $0 } print(flattenedArray) // 输出:[1, 2, 3, 4, 5]
- 解释:
flatMap对每个子数组直接取值,并展平嵌套结构。
3.2 过滤 nil 的可选值数组
swift
CopyEdit
let optionalArray: [Int?] = [1, nil, 3, nil, 5] let result = optionalArray.flatMap { $0 } print(result) // 输出:[1, 3, 5]
- 解释:
flatMap会对每个元素解包,如果是nil则会被丢弃。
compactMap 示例
3.3 处理可选值数组
swift
CopyEdit
let optionalArray: [Int?] = [1, nil, 3, nil, 5] let result = optionalArray.compactMap { $0 } print(result) // 输出:[1, 3, 5]
- 解释:
compactMap专门用于过滤掉nil值,返回非可选值数组。
3.4 不展开嵌套数组
swift
CopyEdit
let nestedArray = [[1, 2], nil, [3, 4]] let result = nestedArray.compactMap { $0 } print(result) // 输出:[[1, 2], [3, 4]]
- 解释:
compactMap不会展平嵌套结构,仅对数组中的元素过滤掉nil。
4. 什么时候用 flatMap 和 compactMap?
使用 flatMap 的场景
-
嵌套数组需要展平:
- 例如将二维数组转为一维数组。
swift
CopyEdit
let nestedArray = [[1, 2], [3, 4]] let flattenedArray = nestedArray.flatMap { $0 } print(flattenedArray) // [1, 2, 3, 4] -
同时映射和展平操作:
- 当映射的结果本身是数组,并希望展开成一维数组。
swift
CopyEdit
let strings = ["apple", "banana"] let characters = strings.flatMap { $0.map { String($0) } } print(characters) // ["a", "p", "p", "l", "e", "b", "a", "n", "a", "n", "a"]
使用 compactMap 的场景
-
过滤
nil值:- 当数据中包含可选值,需要去除所有
nil并保留非空值。
swift
CopyEdit
let optionalNumbers: [Int?] = [1, nil, 3, nil, 5] let nonNilNumbers = optionalNumbers.compactMap { $0 } print(nonNilNumbers) // [1, 3, 5] - 当数据中包含可选值,需要去除所有
-
映射并过滤结果为
nil的数据:- 如果闭包操作可能返回
nil,可以用compactMap过滤掉结果中的nil。
swift
CopyEdit
let strings = ["1", "two", "3", "four"] let numbers = strings.compactMap { Int($0) } print(numbers) // [1, 3] - 如果闭包操作可能返回
5. flatMap 在 Swift 5 的细化
在 Swift 5 中,flatMap 的功能被细化:
- 对于嵌套数组的展开,仍然使用
flatMap。 - 对于处理可选值数组,推荐使用
compactMap。
虽然 flatMap 仍然可以处理 nil 的过滤,但为了代码的可读性,compactMap 更加语义化。
6. 总结对比
| 特性 | flatMap | compactMap |
|---|---|---|
| 核心功能 | 映射 + 展平 | 映射 + 过滤 nil |
| 嵌套数组展开 | 是 | 否 |
过滤 nil | 支持(但非专注) | 是 |
| 推荐用途 | 嵌套结构展平 | 处理可选值或映射过滤 nil 的场景 |
4o