令你极度舒适的Swift集合类高阶函数
在Swift
的集合类型中,有许多十分便捷的函数。相比于Objective-C
,这些高阶函数会引起你的极度舒适。因为在Swift
的许多函数中引入了闭包元素,这就直接造就了它的灵活性,简直就是极致的便捷。
下面就来对Swift
集合类中的这些高阶函数进行总结。
// 全文的基础数据
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
1.sort函数
对原集合进行给定条件排序。
无返回值,直接修改原集合,所以这个集合应该是可变类型的。
var sortArr = numbers
numbers.sort { a, b inreturn a < b
}
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
另外,系统还定义了一个sort()
函数,即对集合进行升序排序的函数。但这个函数并不是上面函数不传入缺省值的情况,而是另外一个函数。
var sortArr2 = numbers
numbers.sort()
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2.sorted函数
sorted函数
与sort函数
对应。
将集合进行给定条件排序,返回一个新的集合,不修改原集合。
let sortedArr = numbers.sorted { a, b inreturn a > b
}
// [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]// sorted()函数
let sortedArr2 = numbers.sorted()
// [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]// 闭包简写
let sortedArr3 = sortedArr2.sorted(by: >)
// [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
闭包的省略写法
因为在高阶函数中大部分都使用了闭包,所以我认为有必要做一个铺垫,以更好地理解本文。清楚闭包简写的请跳过本段,直奔第3条
。
由于sort函数
使用了闭包,所以自主定义的闭包可以简写为如下格式:
numbers.sort(by: >)
// [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
以上述方法为例,一个完整的闭包应该是这样的:
numbers.sorted { (a: Int, b: Int) -> Bool inreturn a > b
}
然后,可以省略闭包中的返回值。
numbers.sorted { (a: Int, b: Int) inreturn a > b
}
然后,再可以省略形参的类型,让编译器去自主推断。
numbers.sorted { a, b inreturn a > b
}
再然后,还可以让$0
,$1
…来代替第一个,第二个形参,以此类推。
numbers.sorted { return $0 > $1 }
再然后,省略return
。一般的,到这里也就足够简化了。毕竟在实际开发中我们需要使用闭包中的参数进行一些复杂的判断。
numbers.sorted { $0 > $1 }
如果你不需要复杂的判断,那么还可以写成下面这样,代表降序排序。
numbers.sorted(by: >)
3.map函数
按照闭包中的返回结果,将集合中对应元素进行替代,也就是映射函数。
// 数组数值转换为其各自平方
let mapArr = numbers.map { $0 * $0 }
// [49, 36, 100, 81, 64, 1, 4, 9, 16, 25]
可选类型的 map, flatMap函数
另外,不仅CollectionType
有map
和flatMap
函数,在Optional
类型中,也存在这两个函数。
它们的作用是对可选类型就行解包操作,若有值则进入闭包,并返回一个 Optional
类型;若为nil,则直接返回当前可选类型的nil。
let num1: Int? = 3
let num2: Int? = nillet numMap1 = num1.map {$0 * 2
}
numMap1 // 6
type(of: numMap1) // Optional<Int>.Typelet numMap2 = num2.map {$0 == 0
}
numMap2 // nil
type(of: numMap2) // Optional<Bool>.Typelet numFlatMap1 = num1.flatMap {$0 * $0
}
numFlatMap1 // 9
type(of: numFlatMap1) // Optional<Int>.Typelet numFlatMap2 = num2.flatMap {$0 == 0
}
numFlatMap2 // nil
type(of: numFlatMap2) // Optional<Bool>.Type
还有一种应用场景,就是解析可选类型的时候,map
和flatMap
函数会让你的代码更加优雅。
举个例子,当解析并判断可选类型的时候,你可能会经过一堆if
或者guard
判断,如下所示:
func loadURL(url: URL) {print(url.absoluteString)
}let urlStr: String? = "https://github.com/wangyanchang21"
guard let siteStr = urlStr else {assert(false)
}
guard let url = URL(string: siteStr) else {assert(false)
}
loadURL(url: url)
如果使用map
和flatMap
函数的话,就会有十分优雅的感觉。
// 这行优雅的代码代替上面的代码
urlStr.flatMap(URL.init).map(loadURL)
但有一点需要注意,这里 map替换 flatMap会报错, 原因在于 flatMap闭包可以返回 nil, 而 map闭包不可以。就如下面的代码编译不会通过:
// compile error
// urlStr.map(URL.init).map(loadURL)
再举一个例子:
let date: Date? = Date()
let format = date.map(DateFormatter().string)
我在函数的闭包形式中也写过这种优雅的写法具体是怎么回事。有兴趣可以了解一下。
4.flatMap函数
也是一种映射函数,这个函数具有多重功能,所以也就造成了这个函数有一个历史问题,稍后会解释。
第一种情况,解析首层元素,若有nil则过滤,就不会降维
let optLatticeNumbers = [[1, Optional(2), 3], [3, nil, 5], nil]
// 解析首层元素, 若有nil则过滤, 就不会降维
let flatMapArr2 = optLatticeNumbers.flatMap { $0 }
// [[1, 2, 3], [3, nil, 5]]
第二种情况,解析首层元素,若没有nil,则会降维
let latticeNumbers = [[1, Optional(2), 3], [3, nil, 5]]
// 解析首层元素, 若没有nil, 则会降维
let flatMapArr = latticeNumbers.flatMap { $0 }
// [1, 2, 3, 3, nil, 5]
所以flatMap
的功能就有两个了,一个功能是解析并过滤首层元素为nil的元素,一个功能是对多维集合进行降维。原因是,其实这是两个功能是两个函数
,只是在调用时代码上没有区别。
flatMap和compactMap的关系
但从表面上看,flatMap
函数违背了单一功能原则,将过滤nil
和降维
两个功能于隐藏条件中进行判定。这也就是那个历史问题。
因此,为了将过滤nil
和降维
两个功能于区分开,swift4.1开始,就只保留了降维的flatMap函数
,并弃用了过滤nil的flatMap函数
,又用开放的新函数compactMap
来替代弃用的函数。
所以,当需要过滤nil的时候,请使用compactMap
函数;当需要进行降维时,请使用flatMap
函数。这也就是flatMap
和compactMap
之间的区别。
5.compactMap函数
Swift4.1开始开放的一种映射函数,会解析并过滤首层元素为nil的元素。
let compactMapArr = optLatticeNumbers.compactMap { $0 }
// [[1, 2, 3], [3, nil, 5]]
let compactMapArr2 = latticeNumbers.compactMap { $0 }
// [[1, 2, 3], [3, nil, 5]]
compactMap
函数作为过滤nil的flatMap
函数的替代函数。当集合中的元素为一个一维集合,他们之间的功能是没有差别的。
let flatNumbers = [1, Optional(2), 3, nil, Optional(5), nil]let flatMapArr = latticeNumbers.flatMap { $0 }
// [1, 2, 3, 5]
let compactMapArr = optLatticeNumbers.compactMap { $0 }
// [1, 2, 3, 5]
6.filter函数
按照条件进行元素过滤。
let filterArr = numbers.filter { num inreturn num < 3 || num > 8
}
// [10, 9, 1, 2]
7.reduce函数
以指定参数为基础,按照条件进行拼接
let reduceNumber = numbers.reduce(100) { result, num inreturn result + num
}
// 155let reduceString = ["C", "O", "D", "E"].reduce("word: ") { result, num inreturn result + num
}
// "word: CODE"
8.prefix函数
正向取满足条件的元素,进行新集合创建。一旦出现不满足条件的元素,则跳出循环,不再执行。
let prefixArr = numbers.prefix { $0 < 10 }
// [7, 6]
prefix
相关函数:
upTo
: 正向取元素创建数组, 包含小于指定index的元素
let prefixUpToArr = numbers.prefix(upTo: 5)
// [7, 6, 10, 9, 8]
through
: 正向取元素创建数组, 包含小于等于指定index的元素
let prefixThroughArr = numbers.prefix(through: 2)
// [7, 6, 10]
maxLength
: 正向取元素创建数组, 包含指定的元素个数
let prefixMaxLengthArr = numbers.prefix(6)
// [7, 6, 10, 9, 8, 1]
9.drop函数
与prefix函数
对应。正向跳过满足条件的元素,进行新集合创建。一旦出现不满足条件的元素,则跳出循环,不再执行。
let dropArr = numbers.drop { $0 < 10 }
// [10, 9, 8, 1, 2, 3, 4, 5]
drop
相关函数:
dropFirst
: 正向跳过元素创建数组, 跳过指定元素个数, 缺省值为1
let dropFirstArr = numbers.dropFirst(3)
// [7, 6, 10, 9, 8]
dropLast
: 返向跳过元素创建数组, 跳过指定元素个数, 缺省值为1
let dropLastArr = numbers.dropLast(5)
// [7, 6, 10, 9, 8]
10.first函数
正向找出第一个满足条件的元素。
let first = numbers.first { $0 < 7 }
// 6
11.last函数
与first
函数对应。反向找出第一个满足条件的元素。
let last = numbers.last { $0 > 5 }
// 8
12.firstIndex函数
正向找出第一个满足条件的元素下标。
let firstIndex = numbers.firstIndex { $0 < 7 }
// 1
13.lastIndex函数
反向找出第一个满足条件的元素下标。
let lastIndex = numbers.lastIndex { $0 > 5 }
// 4
14.partition函数
按照条件进行重新排序,不满足条件的元素在集合前半部分,满足条件的元素后半部分,但不是完整的升序或者降序排列。
返回值为排序完成后集合中第一个满足条件的元素下标。
var partitionNumbers = [20, 50, 30, 10, 40, 20, 60]
let pIndex = partitionNumbers.partition { $0 > 30 }
// partitionNumbers = [20, 20, 30, 10, 40, 50, 60]
// pIndex = 4
15.min函数
按条件排序后取最小元素。
let min = numbers.min { $0 % 5 < $1 % 5 }
// 10
min()
函数,自然升序取最小。
let minDefault = numbers.min()
// 1
16.max函数
按条件排序后取最大元素。
let maxDictionary = ["aKey": 33, "bKey": 66, "cKey": 99]
let max = maxDictionary.max { $0.value < $1.value }
// (key "cKey", value 99)
max()
函数,自然升序取最大。
let maxDefault = numbers.max()
// 10
17.removeAll函数
移除原集合中所有满足条件的元素。
无返回值,直接修改原集合,所以这个集合应该是可变类型的。
var removeArr = numbers
removeArr.removeAll { $0 > 6 }
// [6, 1, 2, 3, 4, 5]
18.集合遍历
forEach
函数:
numbers.forEach { num inprint(num)
}
for-in
函数:
for num in numbers where num < 5 {print(num)
}
与enumerated()
函数配合使用:
for (index, num) in numbers.enumerated() {print("\(index)-\(num)")
}
关于集合遍历的性能问题,可以看这里enumerated() 和 enumerateObjectsUsingBlock。
19.shuffled函数
shuffled
函数,打乱集合中元素的的顺序。
let ascendingNumbers = 0...9
let shuffledArr = ascendingNumbers.shuffled()
// [3, 9, 2, 6, 4, 5, 0, 1, 7, 8]
20.contains函数
contains
函数,判断集合中是否包含某元素。
let containsBool = numbers.contains(8)
let containsBool1 = numbers.contains(11)
// true
// false
21.split和joined函数
split
函数,字符串的函数,按条件分割字符串,为子字符串创建集合。与Objective-C
中的componentsSeparatedByString:
方法类似。
let line = "123Hi!123I'm123a123coder.123"
let splitArr = line.split { $0.isNumber }
// ["Hi!", "I'm", "a", "coder."]// 也可指定字符
let splitArr2 = line.split(separator: "1")
// ["23Hi!", "23I'm", "23a", "23coder.", "23"]
joined
函数,数组元素连接指定字符拼接成一个字符串。与Objective-C
中的componentsJoinedByString:
方法类似。
let joined = splitArr.joined(separator: "_")
// "Hi!_I'm_a_coder."// 也可以只传入字符
let joined2 = splitArr2.joined(separator: "#")
// "23Hi!#23I'm#23a#23coder.#23"
22.zip函数
将两个数组合并为一个元组组成的数组。
let titles = ["aaa", "bbb", "ccc"]
let numbers = [111, 222, 333]
let zipA = zip(titles, numbers)
for (title, num) in zipA {print("\(title)-\(num)")
}
打印结果:
aaa-111
bbb-222
ccc-333
令你极度舒适的Swift集合类高阶函数相关推荐
- Swift的高阶函数
Swift的高阶函数 swift常用高阶函数 1. map 2. flatMap 3. filter 4. reduce swift常用高阶函数 swift中比较常用的高阶函数有:map.flatMa ...
- Swift 常用高阶函数
Swift 常用高阶函数 map函数 对每一个元素进行运算 计算每一个元素的count 对元素进行大小写变换 转换类型 sorted函数 从小到大排序 从大到小排序 flatMap函数 降维 过滤元素 ...
- Swift 基础 高阶函数 forEach filter map compactMap compactMapValues flatMap reduce sort sorted shuffled ...
一直觉得自己写的不是技术,而是情怀,一个个的教程是自己这一路走来的痕迹.靠专业技能的成功是最具可复制性的,希望我的这条路能让你们少走弯路,希望我能帮你们抹去知识的蒙尘,希望我能帮你们理清知识的脉络,希 ...
- kotlin修炼指南8—集合中的高阶函数
点击上方蓝字关注我,知识会给你力量 Kotlin对集合操作类新增了很多快捷的高阶函数操作,各种操作符让很多开发者傻傻分不清,特别是看一些Kotlin的源码或者是协程的源码,各种眼花缭乱的操作符,让代码 ...
- swift 数组高阶使用(一)
2019独角兽企业重金招聘Python工程师标准>>> ###swift 数组高阶使用 在使用数组的时候,我们通常会通过下标的方式来获得数组中的元素,但是有时候我们会需求会非常变态, ...
- Swift 烧脑体操(三) - 高阶函数
前言 \\ Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说 ...
- Swift 中的高阶函数
一.概念 高阶函数是将一个或多个函数作为参数或返回一个函数作为其结果的函数 二.Swift的集合类型中的高阶函数 1.Map 对于原始集合里的每一个元素,以一个变换后的元素替换之形成一个新的集合 le ...
- kotlin高阶函数的初级理解
1.定义 如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数. 系统中已经有很多,示例:库函数 在 Standard.kt 标准库中提供了一些便捷的内置高阶函数 ...
- Go 学习笔记(61)— Go 高阶函数、函数作为一等公民(函数作为输入参数、返回值、变量)的写法
函数在 Go 语言中属于"一等公民(First-Class Citizen)"拥有"一等公民"待遇的语法元素可以如下使用 可以存储在变量中: 可以作为参数传递给 ...
- 2021年大数据常用语言Scala(三十七):scala高级用法 高阶函数用法
目录 高阶函数用法 作为值的函数 匿名函数 柯里化(多参数列表) 闭包 高阶函数用法 Scala 混合了面向对象和函数式的特性,在函数式编程语言中,函数是"头等公民",它和Int. ...
最新文章
- 简化可视SLAM应用程序的开发
- linux远程安装本机软件,我的电脑怎样让对方远程装软件?
- ​cglib实现动态代理构建带参数的代理实例
- 网络和计算机管理制度,网络和计算机使用管理制度
- win10 安装 tensorflow gpu 版
- Docker 搜索镜像
- java swing 导出文件_java swing (一) 导出excel文件并打开
- python获取当前目录_又有几个Python小技巧分享
- 深入理解Lock的底层实现原理
- mysql性能优化的最佳20条经验_MySQL性能优化的最佳20+条经验
- iOS开发之审核时间
- HTML兼容IE版本问题
- 天正双击墙体不能编辑_【盘点】CAD、天正、Ps 快捷键最全汇总!
- 吐血整理的大数据学习资源大全
- 苹果开发者过期续费流程
- 怎么制作位置分布图,怎么画网点分布图
- 技术笔记:Indy IdSMTP支持腾讯QQ邮箱邮件发送
- PowerManagerService分析(二)之updatePowerStateLocked()核心
- python 答题卡识别_opencv+python机读卡识别整合版
- deck.gl 调研