一、contains
返回一个布尔值,指示序列的每个元素是否满足给定的条件。如果有一个满足即返回。
let expenses = [21.37, 55.21, 9.32, 10.18, 388.77, 11.41]
let hasBigPurchase = expenses.contains { $0 > 100 }
// 'hasBigPurchase' == true
Sequence
协议源码
@inlinable
public func contains(_ element: Element) -> Bool {
if let result = _customContainsEquatableElement(element) {
return result
} else {
return self.contains { $0 == element }
}
}
@inlinable
public func contains(
where predicate: (Element) throws -> Bool
) rethrows -> Bool {
for e in self {
if try predicate(e) {
return true
}
}
return false
}
二、allSatisfy
返回一个布尔值,指示序列的每个元素是否满足给定的条件。需要所有元素都满足。
let names = ["Sofia", "Camilla", "Martina", "Mateo", "Nicolás"]
let allHaveAtLeastFive = names.allSatisfy({ $0.count >= 5 })
// allHaveAtLeastFive == true
Sequence
协议源码
allSatisfy
里面调用了contains
方法
@inlinable
public func allSatisfy(
_ predicate: (Element) throws -> Bool
) rethrows -> Bool {
return try !contains { try !predicate($0) }
}
三、reversed
返回一个数组,该数组以相反的顺序包含此序列的元素。
let list = [1, 2, 3, 4, 5]
let ret = list.reversed()
print(Array(ret))
---console
[5, 4, 3, 2, 1]
Sequence
协议源码
@inlinable
public __consuming func reversed() -> [Element] {
// FIXME(performance): optimize to 1 pass? But Array(self) can be
// optimized to a memcpy() sometimes. Those cases are usually collections,
// though.
var result = Array(self)
let count = result.count
for i in 0..<count/2 {
result.swapAt(i, count - ((i + 1) as Int))
}
return result
}
四、lexicographicallyPrecedes
返回一个布尔值,该值指示在字典顺序(字典)中该序列是否在另一个序列之前,使用给定条件语句比较元素。
let list = [1, 2, 3, 4, 5]
let list2 = [2, 2, 3, 5]
let ret1 = list.lexicographicallyPrecedes(list2)
let ret2 = list2.lexicographicallyPrecedes(list)
print(ret1, ret2)
---console
true false
Sequence
协议源码
@inlinable
public func lexicographicallyPrecedes<OtherSequence: Sequence>(
_ other: OtherSequence
) -> Bool where OtherSequence.Element == Element {
return self.lexicographicallyPrecedes(other, by: <)
}
@inlinable
public func lexicographicallyPrecedes<OtherSequence: Sequence>(
_ other: OtherSequence,
by areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows -> Bool
where OtherSequence.Element == Element {
var iter1 = self.makeIterator()
var iter2 = other.makeIterator()
while true {
if let e1 = iter1.next() {
if let e2 = iter2.next() {
if try areInIncreasingOrder(e1, e2) {
return true
}
if try areInIncreasingOrder(e2, e1) {
return false
}
continue // Equivalent
}
return false
}
return iter2.next() != nil
}
}
Swift Sequence(序列) & Collection(集合) & 高阶函数
前言
序列和集合是一门语言中重要的组成部分,下面我们就通过这篇文章来看看Swift
中的序列和集合。
首先我们来看一段简单的代码:
let numbers = [1,2,3,4]
for num in numbers {
print(num)
}
这是一段简单的通过for...in
遍历数组中元素的代码,那么这个for...in
在底层是如何实现的呢?下面我们通过sil
代码
这里贴关键的代码:
- 首先调用了
Collection
协议中的makeIterator()
方法,创建了一个indexingIterator
- 接下来调用
IndexingIterator.next()
方法来不断拿到元素 - 所以我们平时使用的
for...in
就是个语法糖,底层是通过迭代器来实现遍历的。
下面我们通过Swift源码来看看,首先找到Collection.swift
文件:
Xnip2021-03-23_15-02-48
下面我们就开始研究一下Sequence
1. Sequence
1.1 IteratorProtocol
首先我们找到Sequence.swift
文件,首先看到的就是IteratorProtocol
协议:
public protocol IteratorProtocol {
associatedtype Element
mutating func next() -> Element?
}
以上就是协议定义的源码,一个关联类型Element
和一个mutating
的next
方法,返回一个Element
。
1.2 Sequence
继续向下看,就可以看到Sequence
的源码:
Sequence
可以看到Sequence
协议:
- 可以表达一个有限或者无限的集合
- 它只提供集合中的元素和如何访问这些元素的接口
1.3 小结
总的来说:IteartorProtocol
是一个一次提供一个序列值的类型,它和Sequence
协议时息息相关的,Sequence
每次通过创建迭代器来访问序列中的元素。
所以我们每次在使用for...in
的时候,其实都是使用这个集合的迭代器来遍历当前的集合或者序列中的元素。
1.4 自定义Sequence
下面我们来自定义一个Sequence
,假设我们要用一个结构体来模拟一个集合,对于一个给定的初始值,那么当前集合中包含从0...count
的整形集合。
struct LGSequence: Sequence {
// 指定Element类型为Int
typealias Element = Int
var arrayCount: Int
init(_ count: Int) {
self.arrayCount = count
}
// 为Sequence创建一个迭代器,来遍历Seq中的元素
func makeIterator() -> LGIterator{
return LGIterator(self)
}
}
/// 迭代器,遵循 IteratorProtocol 协议
struct LGIterator: IteratorProtocol {
// 指定Element类型为Int
typealias Element = Int
let seq: LGSequence
var count = 0
// 提供一个构造方法,方便初始化迭代器
init(_ sequence: LGSequence) {
self.seq = sequence
}
// next 方法以count作为自增的操作
mutating func next() -> Int? {
guard count < self.seq.arrayCount else {
return nil
}
count += 1
return count
}
}
let seq = LGSequence.init(10)
for element in seq {
print(element)
}