89-Swift之map和flatMap函数的介绍

引言

在使用 Swift 语言开发中对集合类型的数据操作也是频频使之。Swift 是一种支持函数式编程的语言,它提给开发者许多对集合类型操作的函数如: map 、 flatMap 、Filter 、Reduce 等等。今天我们主要介绍 mapflatMap 两各函数。

map 的介绍

map 的作用

下面我将举出一个例子来阐述 map 的作用,例子如下:

// TODO: 创建一个数组
let number = [9 ,99 ,999 , 9999]
// TODO: 我们要将 ‘number’ 数组中每一个对象都加 ‘1’
// 古老的方法
var handleNumber:[Int] = []
for item in number {
     handleNumber.append(item + 1)
}
print("古老方法结果:")
print(handleNumber)

// map 方法一
handleNumber = number.map({ (item) -> Int in
    return item + 1
})
print("方法一结果:")
print(handleNumber)

// map 方法二
handleNumber = number.map({$0+1})
print("方法二结果:")
print(handleNumber)

// map 方法三
handleNumber = number.map(){$0 + 1}
print("方法三结果:")
print(handleNumber)

// MARK: 输出结果
/*
古老方法结果:
[10, 100, 1000, 10000]
方法一结果:
[10, 100, 1000, 10000]
方法二结果:
[10, 100, 1000, 10000]
方法三结果:
[10, 100, 1000, 10000]
*/

测试实例图如下:


5B9B1370-F360-4813-BD37-4E012CEB1E82.png

从上面代码来看 map 函数接受一个闭包作为参数来对数组中的每一个元素做闭包函数处理,类似对数组中每一个元素做一个映射。总结: map 函数的作用是可以对集合类型数据元素进行遍历并可执行闭包函数操作。

map 函数的定义

// TODO: Map 的定义
public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]

//  TODO: 定义函数中参数的解释
//   T : 代表的是数据类型; 数据泛型类型的标示符。
//  <T> : map 函数后面的 <T> 是函数定义的一个占位类型名。不会查找 T 的类型。
//  Element : 是要被操作集合中的元素。
//  [T] : 是代表的是存储 T 类型的数组。
//  throws : 是表示调用这个闭包函数可能会抛出异常。
//  rethrows : 是表示引用这个闭包函数可能会抛出异常。
//  (Element)->T :是一个闭包函数。
//  (Element)->T)-> [T] : 是一个引用闭包函数。

闭包的写法

  • 闭包的基本写法
{   (Element)-> T in
    // code
}

// TODO: 基本闭包的写法解释
//  Element: Element 可以是输入参数和输出参数,但不可为默认值。如果 Element 是可变参数,那必须将其放到参数的最后一位,否则编辑报错。注释: 元组可以是参数也可以是返回值。
//  in : in 关键字是将闭包的参数引入到函数。
  • 尾随闭包
    如果将闭包作为函数的最后一个参数,那可以省略参数标签。然后将闭包表达式写在调用函数的括号后面。例如下面函数:
func map(_ transform: (Element) -> T) -> [T]

其中 _ transform: (Element) -> T 就是一个闭包。而这个 _ transform: (Element) -> T 闭包它作为 map 函数的最后一个参数。闭包 _ transform: (Element) -> T 的表达式是 Element + 1 。那按尾随闭包的写法如下:

[9,99,999].map(){$0 + 1}

// TODO: 函数解释
// map : 是调用函数。
// $0 + 1 : 是闭包表达式。

由于闭包是函数的最后一个参数也无其他参数。则上面表达式也可以去掉函数的调用括号,直接在大括号中写闭包表达式。这种写法也是推荐写法,其形式如下:

[9,99,999].map {$0 + 1}

$0 的理解

Swift 自动对行内闭包提供简写实际参数名,你也可以通过 $0 , $1 , $2 等名字来引用闭包的实际参数值。使用规则如下:用$0、$1、$2来表示调用闭包中参数,$0指代第一个参数,$1指代第二个参数,$2指代第三个参数,以此类推$n+1指代第n个参数。$后的数字代表参数在闭包中的位置。

map 函数的几种使用情况

  • 遍历集合类型数据中的每一个元素
// TODO: 创建一个数组
let number = [9 ,99 ,999 , 9999]
// TODO: 我们要将 ‘number’ 数组中每一个对象都加 ‘1’
let handleNumber = number.map({$0+1})
print(handleNumber)

// TODO: 输出结果
// [10, 100, 1000, 10000]
  • map 可以是集合中元素类型发生改变
let number = [1 ,2 ,3 , 4]
let handleString = number.map {"NO.\($0)"}
print(handleString)

// TODO: 输出结果
// ["NO.1", "NO.2", "NO.3", "NO.4"]
  • map 可以遍历二位数组中的每一个对象
let twoDimensionalArray = [[1,2,3],[5,65, 665],[9,99,999]]
let handleArray = twoDimensionalArray.map {$0.map { $0 + 1 }}
print(handleArray)

// TODO: 输出结果
// [[2, 3, 4], [6, 66, 666], [10, 100, 1000]]






flatMap 的介绍

flatMap 也是对集合数据类型可以操作函数,那么它与 map 又有什么异同和练习呢?我们看下面的一个例子:

// MARK: 创建数据类型
let flatNumber = [9 ,99 ,999 ,9999 ]

var handleFlatNumber:[Int] = []
// TODO: 第一种写法
handleFlatNumber = flatNumber.flatMap { (item) -> Int in
    return  item + 1
}
print("第一种写法")
print(handleFlatNumber)

// TODO: 第二种写法
handleFlatNumber = flatNumber.flatMap(){$0 + 1}
print("第二种写法")
print(handleFlatNumber)

// TODO: 第三种写法
handleFlatNumber = flatNumber.flatMap {$0 + 1}
print("第三种写法")
print(handleFlatNumber)


// TODO: 输出结果
// 第一种写法
// [10, 100, 1000, 10000]
// 第二种写法
// [10, 100, 1000, 10000]
// 第三种写法
// [10, 100, 1000, 10000]

测试视图如下:


4EB50D1A-498D-46C3-B1F3-100068664247.png

经过上面对 flatMap 的测试可看到 flatMapmap 的作用相同。如果它们作用真的相同,那么为什么还会在出一个 flatMap 函数呢? 那么它们两个的真正区别是什么? 我们继续看下面这个例子:

// MARK: 多维数组的处理
let numbersArray = [[5 ,65 ,665 ],[9, 99 ,999 ]]
// TODO: map 的处理
let mapHandleArray = numbersArray.map {$0.map{$0 + 1}}
print("map 处理结果")
print(mapHandleArray)

// TODO: flatMap 的处理
let flatMapHandleArray = numbersArray.flatMap{$0.flatMap{$0 + 1}}
print("flatMap 处理结果")
print(flatMapHandleArray)

// TODO: 输出结果
// map 处理结果
// [[6, 66, 666], [10, 100, 1000]]
// flatMap 处理结果
// [6, 66, 666, 10, 100, 1000]

what ? why ? 不是说 mapflatMap 的作用相同吗? 这怎么出现不同的结果?其实,这就能看出 flatMapmap 对二位数组的处理不同的差异了。从上面的测试结果可以看到 flatMap 函数对二位数组进行了降维操作。那为什么 flatMap 函数可以使数组降维操作?我们来看看 flatMap 的定义:

// 定义一
public func flatMap(_ transform: (Element) throws -> String?) rethrows -> [String]

// 定义二
public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

// 定义三
public func flatMap<SegmentOfResult : Sequence>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Iterator.Element]

// 去除一些修饰词,变换为下面的样式:

// 定义一
public func flatMap((Element) -> String?) -> [String]

// 定义二
public func flatMap<ElementOfResult>((Element) -> ElementOfResult?) -> [ElementOfResult]

// 定义三
public func flatMap<SegmentOfResult : Sequence>( (Element) -> SegmentOfResult) -> [SegmentOfResult.Iterator.Element]

从上面的定义可以看出 定义一 和定义二是相同的。看下面的例子:

let stringArray = ["100" ,"" ,"200" ,"300" ,""]
let stringHandleArray = stringArray.flatMap { (item) -> Int?  in
    Int(item)
}
print(stringHandleArray)

// TODO: 输出结果
// [100, 200, 300]

从上面的输出结果我们可以看到 可选类型的数据被解包。其中 Int(item) 这个是可选类型,它有可能不成功,为nil 。上面的例子是调用 flatMap 的第二种定义。我们继续再看下面的一个例子:

let exampleArray = [ 1 , "2" , 3 , 9] as [Any]
let handleExpArray = exampleArray.flatMap {(item) in
    Array(repeatElement(item, count: 2))
}
print(handleExpArray)

// TODO: 输出结果
// [1, 1, "2", "2", 3, 3, 9, 9]

从上面返回结果可以看出 flatMap 函数使 ** exampleArray** 中的数据重复2次生成一个子数组(SegmentOfResult),而flatMap 函数要输出 [SegmentOfResult.Iterator.Element] 类型的一维数组。所以才有上面的输出结果。

flatMap 的用途

  • 可以遍历集合类型对象的每一个元素
let flatNumberArray = [9 , 99 , 999 ,9999]
let handleFlatMapNumberArray = flatNumberArray.flatMap({$0 + 1 })
print(handleFlatMapNumberArray)

// TODO: 输出结果
// [10, 100, 1000, 10000]
  • 使二维数组降为一维数组
// MARK: 多维数组的处理
let numbersArray = [[5 ,65 ,665 ],[9, 99 ,999 ]]
let mapHandleArray = numbersArray.map {$0.map{$0 + 1}}
print(mapHandleArray)

// TODO: 输出结果
// [6, 66, 666, 10, 100, 1000]
  • 可以移除集合数据中元素不存在元素
let stringArray = ["100" ,"" ,"200" ,"300" ,""]
let stringHandleArray = stringArray.flatMap { (item) -> Int?  in
    Int(item)
}
print(stringHandleArray)

// TODO: 输出结果
// [100, 200, 300]
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容

  • 一、数组中的 map 和 flatMap 数组中的 map 对数组元素进行某种规则的转换,例如: 二、 flatM...
    kmplayer阅读 4,022评论 0 6
  • map 和 flatMap 是 Swift 中两个常用的函数,它们体现了 Swift 中很多的特性。对于简单的使用...
    SwiftCafe阅读 1,568评论 5 16
  • 粗鄙的简介 以下转自CSDN的一篇博博客http://blog.csdn.net/fish_yan_/articl...
    小白猿阅读 468评论 0 2
  • 今天周日,没联系, 相处半年的正确打开方式到底是什么样子的 我想有人陪我 电话来了。。。 我不知道他。。。。
    汐不渝阅读 222评论 0 0
  • 我体验到的痛苦是什么? 与亲人分离的痛苦,亲人朋友因身体疾病和心理疾病的痛苦,身体机能衰老的无助的痛苦! 什么事情...
    竺子阅读 195评论 0 0