Swift flatMap详解
Swift flatMap详解
- Swift flatMap详解
- flatMap 的其中一个重载
- flatMap 的另一个重载
Swift flatMap详解
先看下flatMap的用法
Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element] where S : Sequence
Optional.flatMap<U>(_: (Wrapped) -> U?) -> U?
Sequence.flatMap<U>(_: (Element) -> U?) -> [U]
Map 可以对一个集合类型的所有元素做一个映射操作, 那么 flatMap 跟Map有什么区别呢?
让我们来看一个 flatMap 的用法:
result = numbers.flatMap { $0 + 1 }
// [2,3,4,5]
同样的数组使用 flatMap 进行处理,得到的结果是一样的,那 flatMap 和 map 到底有什么区别呢?
让我们再看一个场景
let numbersCompound = [[1,2,3],[4,5,6]];
var res = numbersCompound.map { $0.map{ $0 + 1 } }
// [[2,3,4], [5,6,7]]
var flatRes = numbersCompound.flatMap { $0.map{ $0 + 1 } }
// [2,3,4,5,6,7]
这里就看出差别了,对于二维数组来说,Map和flatMap的结果就不同了。
相比于Map,flatMap 依然会遍历数组的元素,并对这些元素执行闭包中定义的操作。 但唯一不同的是,它对最终的结果进行了所谓的 “降维” 操作。 本来原始数组是一个二维的, 但经过 flatMap 之后,它变成一维的了。
下面咱们再来看一下 flatMap 的函数定义
func flatMap(transform: (Self.Generator.Element) throws -> T?) -> [T]
func flatMap(transform: (Self.Generator.Element) -> S) -> [S.Generator.Element]
flatMap 的其中一个重载
flatMap 有两个重载。 参照我们刚才的示例,我们调用的其实是第二个重载,flatMap 的闭包接受的是数组的元素,但返回的是一个 SequenceType 类型,也就是另外一个数组。 这从我们刚才这个调用中不难看出我们传入给 flatMap 一个闭包 $0.map{ $0 + 1 } , 这个闭包中,又对 $0 调用了 map 方法, 从 map 方法的定义中我们能够知道,它返回的还是一个集合类型,也就是 SequenceType。 所以我们这个 flatMap 的调用对应的就是第二个重载形式。
那么为什么 flatMap 调用后会对数组降维呢? 我们可以从它的源码中窥探一二(Swift 不是开源了吗~)。
文件位置: swift/stdlib/public/core/SequenceAlgorithms.swift.gyb
extension Sequence {//...
public func flatMap(
@noescape transform: (${GElement}) throws -> S
) rethrows -> [S.${GElement}] {var result: [S.${GElement}] = []
for element in self {result.append(contentsOf: try transform(element))
}
return result
}
//...
}
这就是 flatMap 的完整源码了, 它的源码也很简单, 对遍历的每一个元素调用try transform(element)。
transform 函数就是我们传递进来的闭包。
然后将闭包的返回值通过result.append(contentsOf:)
函数添加到 result 数组中。
那我们再来看一下result.append(contentsOf:)
都做了什么, 它的文档定义是这样:
Append the elements of newElements to self.
简单说就是将一个集合中的所有元素,添加到另一个集合。 还以我们刚才这个二维数组为例:
let numbersCompound = [[1,2,3],[4,5,6]];
var flatRes = numbersCompound.flatMap { $0.map{ $0 + 1 } }
// [2,3,4,5,6,7]
flatMap 首先会遍历这个数组的两个元素 [1,2,3] 和 [4,5,6], 因为这两个元素依然是数组, 所以我们可以对他们再进行 map 操作: $0.map{ $0 + 1 }。
这样, 内部的 $0.map{ $0 + 1 } 调用返回值类型还是数组, 它会返回 [2,3,4] 和 [5,6,7]。
然后, flatMap 接收到内部闭包的这两个返回结果, 进而调用 result.append(contentsOf:)
将它们的数组中的内容添加到结果集中,而不是数组本身。
那么我们最终的调用结果理所当然就应该是[2,3,4,5,6,7]了。
仔细想想是不是这样呢~
flatMap 的另一个重载
我们刚才分析了半天, 其实只分析到 flatMap 的一种重载情况, 那么另外一种重载又是怎么回事呢:
func flatMap(transform: (Self.Generator.Element) -> T?) -> [T]
从定义中我们看出, 它的闭包接收的是 Self.Generator.Element 类型, 返回的是一个 T? 。 我们都知道,在 Swift 中类型后面跟随一个 ?, 代表的是 Optional 值。 也就是说这个重载中接收的闭包返回的是一个 Optional 值。 更进一步来说,就是闭包可以返回 nil。
我们来看一个例子:
let optionalArray: [String?] = [``"AA"``, nil, ``"BB"``, ``"CC"``]
var optionalResult = optionalArray.flatMap{ $0 }
// ["AA", "BB", "CC"]`
这样竟然没有报错, 并且 flatMap 的返回结果中, 成功的将原数组中的 nil 值过滤掉了。 再仔细观察,你会发现更多。 使用 flatMap 调用之后, 数组中的所有元素都被解包了, 如果同样使用 print 函数输出原始数组的话, 大概会得到这样的结果:
[Optional(``"AA"``), nil, Optional(``"BB"``), Optional(``"CC"``)]
而使用 print 函数输出 flatMap 的结果集时,会得到这样的输出:
["AA", "BB", "CC"]
也就是说原始数组的类型是 [String?] 而 flatMap 调用后变成了 [String]。 这也是 flatMap 和 map 的一个重大区别。 如果同样的数组,我们使用 map 来调用, 得到的是这样的输出:
[Optional(``"AA"``), nil, Optional(``"BB"``), Optional(``"CC"``)]
这就和原始数组一样了。 这两者的区别就是这样。 map 函数值对元素进行变换操作。 但不会对数组的结构造成影响。 而 flatMap 会影响数组的结构。再进一步分析之前,我们暂且这样理解。
flatMap 的这种机制,而已帮助我们方便的对数据进行验证,比如我们有一组图片文件名, 我们可以使用 flatMap 将无效的图片过滤掉:
var imageNames = [``"test.png"``, ``"aa.png"``, ``"icon.png"``]
imageNames.flatMap{ UIImage(named: $0) }
那么 flatMap 是如何实现过滤掉 nil 值的呢? 我们还是来看一下源码:
extension Sequence {// ...
public func flatMap(
@noescape transform: (${GElement}) throws -> T?
) rethrows -> [T] {var result: [T] = []
for element in self {if let newElement = try transform(element) {result.append(newElement)
}
}
return result
}
}
依然是遍历所有元素,并应用try transform(element)
闭包的调用, 但关键一点是,这里面用到了 if let 语句, 对那些只有解包成功的元素,才会添加到结果集中:
if let newElement = try transform(element) {result.append(newElement)
}
这样, 就实现了我们刚才看到的自动去掉 nil 值的效果了。
相关文章:
Swift Map详解.
Swift flatMap详解相关推荐
- iOS swift 蓝牙详解(蓝牙中心demo,蓝牙外设demo(可替代mac蓝牙串口调试工具),蓝牙中心框架,gif演示)
持续更新中... 文章目录 1.gif演示 1.1 蓝牙中心app 1.2 蓝牙外设app(外设被一个设备连接后,还可以被另一个设备连接,但两个同时连会导致连接不稳定,容易断开) 1.3 写write ...
- swift 枚举详解
参考博客:http://c.biancheng.net/cpp/html/2426.html 参考官方文档:https://developer.apple.com/library/ios/docume ...
- 生怕认可java+flatmap,RxJava 操作符flatMap 与 concatMap详解
本文独家发布到公众号:Android技术杂货铺 封面图-pixabay 近两年来,RxJava可以说是异常的火爆,受到众多开发者的追捧与青睐,虽然后入门的门槛较高,学习成本较大,但是还是掀起一场学习R ...
- RxJava flatMap操作符用法详解
RxJava系列文章目录导读: 一.RxJava create操作符的用法和源码分析 二.RxJava map操作符用法详解 三.RxJava flatMap操作符用法详解 四.RxJava conc ...
- swift. 扩展类添加属性_swift中的声明关键字详解
原起 学习swift,swift中的关键字当然要了解清楚了,最近在网上看到了关于声明关键字的文章,整理记录一下. 关键字是类似于标识符的保留字符序列,除非用重音符号(`)将其括起来,否则不能用作标识符 ...
- Swift 中的Closures(闭包)详解
Swift 中的Closures(闭包)详解 在Swift没有发布之前,所有人使用OC语言编写Cocoa上的程序,而其中经常被人们讨论的其中之一 -- Block 一直备受大家的喜爱.在Swift中, ...
- iOS核心动画详解swift版----基础动画
2019独角兽企业重金招聘Python工程师标准>>> iOS核心动画详解swift版---基础动画 创建工程,添加2个ViewController,通过rootViewContro ...
- Swift - SwiftyJSON的使用详解(附样例,用于JSON数据处理)
转自:http://www.hangge.com/blog/cache/detail_968.html Swift - SwiftyJSON的使用详解(附样例,用于JSON数据处理) 2016-01- ...
- Scala系列8:函数式编程之map,flatten,flatmap的使用详解
0.Scala函数式编程 我们将来使用Spark/Flink的大量业务代码都会使用到函数式编程.下面这些事开发中常用的函数式编程.注意这些函数都是操作 Scala 集合的,一般会进行两类操作:转换操作 ...
最新文章
- Unity3D开发——LeRunning的人物角色信息的显示
- java io工作机制_深入分析Java I/O 工作机制
- cs架构用什么语言开发_C、C++、Go 语言、Linux服务器开发高级架构师进阶之路
- css3中的 @Keyframes
- 我总结的几种简单的调用Com组件的方法
- JavaScript - 动态数据
- 解决 SpringBoot 在 JDK8 中 LocalDateTime (反)序列化问题
- 绝佳时机,前所未遇,让艰巨作业全自动化
- 马尔可夫决策过程(MDP)
- ios -- 极光推送《2》--极光推送消息推送成功,但是手机收不到的解决方法
- k8s重要概念及部署k8s集群
- 深入浅出数据分析 Head First Data Analysis Code 一书中的文档下载
- Facebook 数字货币:缘起、意义和后果
- 如何给Layout文件夹分类
- AQS抽象队列同步器
- JRebel-JVMTI [FATAL] Please make sure that ‘C:\Users\\AppData\Roaming\JetBrains\IntelliJIdea2020.
- 设计模式-原型模式C++
- 8086CPU从功能上分为几部分?各部分由什么组成?各部分的功能是什么?
- 模拟CMOS集成电路设计入门学习(13)
- 基于FPGA的DHT11加湿器控制
热门文章
- android 来电拒接_android-如何拒绝/关闭特定的来电号码
- 计算机要通过手机传播,教你一个手机电脑互传功能的小妙招,比蓝牙传输快千倍...
- excel多个窗口独立显示_设置excel工作表打印区域的下技巧
- 如何把查询出的结果按姓氏笔画排序
- 在王者荣耀角度下分析面向对象程序设计B中23种设计模式之代理模式
- iOS图片拉伸(resizableImage)
- 追光几何(EverCraft) 与大疆教育 RoboMaster 建立合作伙伴关系
- C#-Selenium爬虫抓取(一)
- Redis基础都不会,好意思出去面试?
- 互联网实名制部分实施,网民大多心存芥蒂