Swift for循环与高阶函数

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的本质

Swiftfor 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的时候,调用IteratorProtocolnext方法

高阶函数

高阶函数的本质也是函数,它有两个特点

  • 接收函数或者闭包作为参数
  • 返回值是一个函数或者闭包
    这些函数我们通常用来作用于ArraySetDictionary中的每一个元素
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的

你可能感兴趣的:(Swift for循环与高阶函数)