for in
的使用
let numbers = [1,2,3,4,5]
//正序
for number in numbers {
print(number)
}
//倒序
for number in numbers.reversed() {
print(number)
}
//打印索引
for (index,number) in numbers.enumerated() {
print("index = \(index),number = \(number)")
}
//利用高阶函数,本质也是for in
numbers.forEach({print($0)})
numbers.enumerated().forEach { (index,element) in
print(index,element)
}
for in
的本质
Swift
的for in
使用起来很爽,写法跟其它语言差别还是挺大的,它的本质是实现了Sequence
协议,在Swift中数组的本质也是一个结构体,那么我们自己创建一个结构体,然后实现这个协议,让我们自己的结构体能够使用for in
。来理解Sequence
协议和for in
的本质
Sequence协议 的定义
public protocol Sequence {
/// A type representing the sequence's elements.
associatedtype Element where Self.Element == Self.Iterator.Element
/// A type that provides the sequence's iteration interface and
/// encapsulates its iteration state.
associatedtype Iterator : IteratorProtocol
/// Returns an iterator over the elements of this sequence.
func makeIterator() -> Self.Iterator
...
}
IteratorProtocol协议 的定义
public protocol IteratorProtocol {
/// - Returns: The next element in the underlying sequence, if a next element
/// exists; otherwise, `nil`.
mutating func next() -> Self.Element?
}
YMArray & YMIterator
struct YMArray: Sequence {
typealias Element = Int
var arrayCount: Int
init(_ count: Int) {
self.arrayCount = count
}
func makeIterator() -> YMIterator{
return YMIterator(self)
}
}
struct YMIterator: IteratorProtocol {
typealias Element = Int
let seq: YMArray
var count = 0
init(_ sequence: YMArray) {
self.seq = sequence
}
mutating func next() -> Int? {
guard count < self.seq.arrayCount else {
return nil
}
count += 1
return count
}
}
let seq = YMArray.init(5)
for s in seq {
print(s)
}
1
2
3
4
5
Program ended with exit code: 0
总结
数组能够for in
的本质就是实现了Sequence
协议,而Sequence
需要一个迭代器也就是IteratorProtocol
,在for in
的时候,调用IteratorProtocol
的next
方法
高阶函数
高阶函数的本质也是函数,它有两个特点
- 接收函数或者闭包作为参数
- 返回值是一个函数或者闭包
这些函数我们通常用来作用于Array
、Set
、Dictionary
中的每一个元素
Map函数
Map
函数的本质是创建一个新的集合,然后针对原有集合中的元素执行transform
,然后返回新的集合
Map
函数实际是Sequence
协议的拓展
@inlinable public func map(_ transform: (Self.Element) throws -> T) rethrows -> [T]
let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let lowercaseNames = cast.map { $0.lowercased() }
let letterCounts = cast.map { $0.count }
print(lowercaseNames)
print(letterCounts)
["vivien", "marlon", "kim", "karl"]
[6, 6, 3, 4]
flatMap函数
flatMap
函数相比较Map
函数最主要的作用是压平
@inlinable public func flatMap(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
从函数的返回值来看,与Map
函数的区别在于flatMap
函数会将Sequence
中的元素压平,返回的类型会是Sequence
中元素类型集合,而Map
返回的是闭包返回类型T
的数组
let nums = [[1, 2], [3, 4]]
let flatMap_result = nums.flatMap{$0}
print("flatMap_result = \(flatMap_result)")
flatMap_result = [1, 2, 3, 4]
compactMap函数
flatMap
函数还有一个弃用的定义
@available(swift, deprecated: 4.1, renamed: "compactMap(_:)", message: "Please use compactMap(_:) for the case where closure returns an optional value")
public func flatMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
@inlinable public func compactMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
let nums = [1,2,3,nil]
let result = nums.compactMap{$0}
print(result)
[1, 2, 3]
Program ended with exit code: 0
compactMap
函数相比较Map
函数最主要的作用是过滤控制
总结
使用faltMap
当对于序列中元素,转换闭包返回的是序列或者集合时,而你期望得到的结果是一维数组时compactMap
当转换闭包返回可选值并且你期望得到的结果为非可选值的序列时
filter函数
filter
函数也是Sequence
中提供的方法,允许调用者传入一个闭包来过滤集合中的元素
本质就是声音一个空的集合,然后创建迭代器,遍历元素,用闭包表达式做条件判断,符合的加到数组里返回
numbers.filter { ($0 > 3) }
Reduce函数
我们可以使用reduce
函数合并集合中所有的元素,然后创建一个新值
public func reduce(_ initialResult: T, _ nextPartialResult: (T, Output) -> T) -> Result.Failure>.Publisher
let nums = [1, 2 ,3]
let result = nums.reduce(10) { (result, elemnet) -> Int in
print("result:\(result)")
print("elemnet:\(elemnet)")
return result+elemnet
}
//let result = nums.reduce(10, +)
print(result)
result:10
elemnet:1
result:11
elemnet:2
result:13
elemnet:3
16
为了更好的理解reduce
的工作原理,使用reduce
,来实现map
函数,实际上没什么意义,但是据说这是面试题
customMap
第一种写法
let nums = [1, 2 ,3]
func customMap(collection: [Int], transform: (Int) -> Int) -> [Int]{
return collection.reduce([Int]()){
var arr: [Int] = $0
arr.append(transform($1))
return arr
}
}
let result = customMap(collection: nums){
$0 * 2
}
customMap
第二种写法
let result1 = nums.reduce(into: [Int]()){
$0.append($1 * 2)
}
找出数组当中的最大值
let result = [1, 2, 3, 4, 5].reduce(0){
return $0 < $1 ? $1 : $0
}
逆序数组
let result = [1, 2, 3, 4, 5].reduce([Int]()){
return [$1] + $0
}
LazySequence
协议
本质是实现了Sequence
协议,并且重写了迭代器中的next
方法,并保存了当前的集合和闭包函数,当我们访问一个元素的时候,会调用next
方法,此时再调用闭包
//假设我们的数据源量级比较大
let numbers = Array(1...10000)
//而我们不是全部或者马上就需要全部的值,只有用到的时候才进行乘以2
//let mapNumbers = numbers.map({$0 * 2})
let lazyMapNumbers = numbers.lazy.map({$0 * 2})
print(lazyMapNumbers[0])
print(lazyMapNumbers)
2
LazyMapSequence, Int>(_base: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,....
有点类似懒加载,而且如果打印lazyMapNumbers
,发现他并没有变化,但是当get
取值时,是乘2的