集合类
数组
字面量创建
- 可以使用数组字面量来初始化一个数组,它是一种以数组集合来写一个或者多个值的简写方式。数组字面量写做一系列的值,用逗号分隔,用方括号括起来。
let array = [1,2,3,4]
字面量创建空数组
- 创建空数组的时候必须携带类型信息
- 如果内容已经提供了类型信息,比如说作为函数的实际参数或者已经分类了的变量或常量,可以通过空数组字面量来创建一个空数组
let array = []

初始化器
- 使用初始化器有两种方式
- [类型]()
- Array<类型>()
var myArray = [String]()
var myArray2 = Array<String>()
初始化器参数
- init(repeating repeatedValue:Element,count:Int)
- init(arrayLiteral elements:Element...)
let fiveZs = Array(repeating:"Z",count:5)
print(fiveZs)
- init<"S">(_ elements:S) where S:Sequence,Self.Element == S.Element
- init(from decoder:Decoder) throws

数组遍历



索引
- startIndex返回第一个元素的位置,对于数组来说,永远都是0.
- endIndex返回最后一个元素索引+1的位置,对于数组来说,等同于count.
- 如果数组为空,startindex等于endIndex
判断是否包含指定元素
- contains(_:)判断数组是否包含指定元素
- contains(where:)判断数组是否包含复合给定条件的元素
判断所有元素符合某个条件
- allSatisfy(_:)判断数组的每一个元素都符合给定的条件

查找元素
- first返回数组第一个元素(optional),如果数组为空,返回nil
- last返回数组最后一个元素(optional),如果数组为空,返回nil
- first(where:)返回数组第一个符合给定条件的元素(optional)
- last(where:)返回数组最后一个符合给定条件的元素(optional)

查找索引
- firstIndex(of:)返回给定的元素在数组中出现的第一个位置(optional)
- lastIndex(of:)返回给定的元素在数组中出现的最后一个位置(optional)


查找最大最小元素
- min()返回数组中最小的元素
- max()返回数组中最大的元素


数组添加和删除
在末尾添加
- append(_:)在末尾添加一个元素
- append(contentsOf:)在末尾添加多个元素

在任意位置插入
- insert(_:at:)在指定的位置插入一个元素
- insert(contentsOf:at:)在指定位置插入多个元素

字符串也是Collection
- 字符串也是Collection,Element是Character类型

移除单个元素
- remove(at:)移除并返回指定位置的一个元素
- removeFirst()移除并返回数组的第一个元素
- popFirst()移除并返回数组的第一个元素(optional),数组为空返回nil


移除多个元素
- removeFirst(:)移除数组前面多个元素
- removeLast(:)移除数组后面多个元素

- removeSubrange(_:)移除数组中给定范围的元素
- removeAll()移除数字所有元素
- remove(keepingCapacity:)移除数字所有元素,保留数组容量


数组切片 移除多个元素
- ArraySlice是数组或者其他ArraySlice的一段连续切片,和原数组共享内存
- 当要改变ArraySlice的时候,ArraySlice会copy出来,形成单独内存。
- ArraySlice拥有和Array基本完全类似的方法

通过Drop得到ArraySlice
- dropFirst(:)"移除"原数组前面指定个数的元素得到一个ArraySlice
- dropLast(:)"移除"原数组后面指定个数的元素得到一个ArraySlice
- drop(:)"移除"原数组符合指定条件的元素得到一个ArraySlice

通过prefix得到ArraySlice
- prefix()获取数组前面指定个数的元素组成的ArraySlice
- prefix(upTo:)获取数组指定位置(不包含指定位置)前面的元素组成的ArraySlice
- prefix(throught:)获取数组到指定位置(包含指定位置)前面的元素组成的ArraySlice
- prefix(while:)获取数组前面符合条件的元素(到第一个不符合条件的元素截止)组成的ArraySlice

通过suffix得到ArraySlice
- suffix()获取数组后面指定个数的元组组成的ArraySlice
- suffix(from:)获取数组从指定位置到结尾(包含指定位置)的元素组成的ArraySlice

通过Range得到ArraySlice
- 可以通过对数组下标指定Range获取ArraySlice,可以使用闭区间、半开半闭区间、单侧区间、甚至可以只使用...来获取整个数组组成的ArraySlice

ArraySlice转为Array
- ArraySlice无法直接赋值给一个Array的常量或变量,需要使用Array(slice)

ArraySlice和原Array相互独立的
- ArraySlice和原Array是相互独立的,它们添加删除元素不会影响对方

数组重排
数组元素的随机化
- shuffle()在原数组上将数组元素打乱,只能作用在数组变量上。
- shuffled()返回原数组的随机化数组,可以作用在数组变量和常量上

数组的逆序
- reverse()在原数组上将数组逆序,只能作用在数组变量上。
- reversed()返回原数组的逆序"集合表示",可以作用在数组变量和常量上,该方法不会分配新内存空间

数组的分组
- partition(by belongsInSecondPartition:(Element) throws -> Bool)将数组以某个条件分组,数组前半部分都是不符合条件的元素,数组后半部分都是符合条件的元素

数组的排序
- sort()在原数组上将元素排序,只能作用于数组变量
- sorted()返回原数组的排序结果数组,可以作用在数组变量和常量上

交换数组两个元素

字符串数组拼接
- joined()拼接字符串数组里的所有元素为一个字符串
- joined(separator:)以给定的分隔符拼接字符串数组里的所有元素为一个字符串

元素为sequence数组的拼接
- joined()拼接数组里的所有元素为一个更大的sequence
- joined(separator:)以给定的分隔符拼接数组里的所有元素为一个更大的Sequence


数组的底层探秘
数组的协议结构

Sequence(序列)
- 一个序列(sequence)代表的是一系列具有相同类型的值,你可以对这些值进行迭代

IteratorProtocol
- sequence通过创建一个迭代器来提供对元素的访问。迭代器每次产生一个序列的值,并且当遍历序列时对遍历状态进行管理。
- 当序列被耗尽时,next()应该返回nil
protol IteratorProtocol {
associatedtype Element
mutating func next() -> Element?
}
定义自己的Sequence

Collection
- 一个Collection是满足下面条件的Sequence
- 稳定的Sequence,能够被多次遍历且保持一致
- 除了线性遍历以外,集合中的元素也可以通过下标索引的方式被获取到
- 和Sequence不同,Collection类型不能是无限的

Array的迭代器

Array的下标访问

Array的buffer

_ContiguousArrayBuffer

_ContiguousArrayBuffer的 getElement

UnSafeMutablePoint的下标操作

问题:endIndex vs count

索引


课后探索
- 学习removeFirst方法的源码,得出removeFirst的复杂度
- 学习sort方法的源码,了解Array的排序方法
用数组实现栈
Stack
- 栈(Stack)是一种后入先出(Last in First Out)的数据结构,仅限定在栈顶进行插入或者删除操作。栈结构的实际应用主要有数制转换、括号匹配、表达式求值等等。


Queue
- 队列在生活中非常常见。排队等位吃饭、在火车站买票、通过高速路口等,这些生活中的现象很好的描述了对列的特点:先进先出(FIFO,first in first out),排在最前面的先出来,后面来的只能排在后面。


练习
- 尝试改造Stack和Queue的代码让实现SeQuence协议,支持For-In循环
Set(集合)的概念
- Set是指具有某种特定性质的具体的或抽象的对象汇总而成的集体。其中,构成Set的这些对象则称为该Set的元素。
集合的三个特性
- 确定性:给定一个集合,任给一个元素,该元素或者属于或者不属于该集合,二者必居其一
- 互斥性:一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次
- 无序性:一个集合中,每个元素的地位都是相同的,元素之间是无序的
Swift里面的集合
- Swift的集合类型写做Set<Element">",这里的Element是Set要储存的类型。不同与数组,集合没有等价的简写。
创建Set
- 使用初始化器语法来创建一个确定类型的空Set
- 使用数组字面量创建Set

Set类型的哈希值
- 为了能让类型储存在Set当中,他必须是可哈希的--就是说类型必须提供计算它自身哈希值的方法。
- 所有Swift的基础类型(比如String,Int,Double和Bool)默认都是可哈希的,并且可以用于Set或者Dictionary的键。


访问和修改Set(遍历Set)
- 可以使用For-In遍历Set
- 因为Set是无序的,如果顺序遍历Set,使用sorted()方法

访问Set
- 使用count获取Set里元素个数
- 使用isEmpty判断Set是否为空

添加元素
- insert(_:)添加一个元素到Set
- update(with:)如果已经有相等的元素,替换为新元素。如果Set中没有,则插入。

移除元素
- filter(_:)返回一个新的Set,新Set的元素是原始Set符合条件的元素

- remove(_:)从Set当中移除一个元素,如果元素是Set的成员就移除它,并且返回移除的值,如果集合没有这个成员就返回nil。
- removeAll()移除所有元素

基本Set操作

基本Set操作的定义
- intersection(_:)交集,由属于A且属于B的相同元素组成的集合,记作AnB(或BnA)
- union(_:)并集,由所有属于集合A或属于集合B的元素所组成的集合,记作AuB(或BuA)
- symmetricDifference对称(_:)对称差集,集合A与集合B的对称差集定义为集合A与集合B中所有不属于AnB的元素的集合
- subtracting(_:)相对补集,由属于A而不属于B的元素组成的集合,称为B关于A的相对补集,记作A-B或A\B.

Set判断方法
- isSubset(of:)判断是否是另一个Set获取Sequence的子集
- isSuperset(of:)判断是否是另一个Set或者Sequence的超集
- isStrictSubset(of:)和isStrictSuperset(of:)判断是否是另一个Set的子集或者超集,但是又不等于另一个Set
- isDisjoin(with:)判断两个Set是否有公共元素,如果没有返回true,如果有返回false

Set(集合)的算法
思路1-位
- 思路:解这道题的思想本质上就是元素选与不选的问题,于是我们就可以想到用二进制来代表选与不选的情况。"1"代表这个元素已经选择,而"0"代表这个元素没有选择。假如三个元素A B C,那么101就代表B没有选择,所以101代表的子集为AC。

思路2-递归
- 思路:如果只有一个元素,那么它的子集有两个,分别是本身和空集,然后在已经有一个元素的子集的基础上,第二个元素有两种选法,那就是加入到前面的子集里面或者不加入到前面的子集里面,也就是选与不选的问题。而前面的子集一共有两个,对每一个子集都有来自于下一个元素的加入和不加入两种选法。那么就可以得出两个元素的子集一共有四个。依此类推,就可以得出n的元素所有子集(这里n个元素的子集一共有2n个,非空子集一共有2n-1个)。

Set的底层探究
从Set的insert说起

_NativeSet的find方法

HashTable


线性探测的开放寻执法

_NativeSet的insertNew

HashTable的insertNew

_NativeSet的uncheckedInitialize

Dictionary
- 字典储存无序的互相关联的同一类型的键和同一类型的值的集合
- 字典类型的全写方式Dictionary<Key,Value>,简写方式[Key:Value],建议使用简写方式
- 字典的key必须是可哈希的
创建空字典
var dict1 = Dictionary<String,Int>()
var dict2 = [String: Int]()
var dict3: Dictionary<String,Int> = [:]
字面量创建字典
- [key1:value1,key2:value2,key3:value3]
let dict = ["zhangsan":18,"lisi":19,"wangwu":20]
count和isEmpty
- 可以使用count只读属性来找出Dictionary拥有多少元素
- 使用布尔量isEmpty属性检查字典是否为空
遍历字典
- For-in循环
- 可以通过访问字典的keys和values属性来取回可遍历子带你的键或值的集合
- Swift的Dictionary类型是无序的。要以特定的顺序遍历字典的键或值,使用键或值的sorted()

字典的常见操作
添加或更新元素
- 使用下标脚本语法给一个键赋值nil来从字典当中移除一个键值对
- 使用removeValue(forKey:)来从字典里移除键值对。这个方法移除键值对如果他们存在的话,并且返回移除的值,如果值不存在则返回nil
合并两个字典
- merge(_:uniquingKeysWith:)

firstindex
- 虽然字典是无序的,但是每个kv对在扩容之前的位置是稳定的。如果需要保持顺序的kv对可以使用KeyValuePairs

字典的底层探秘
从下标操作谈起

Dictionary._Variant的setValue


_NativeDictionary的_insert

_NativeDictionary的uncheckedInitialize

_NativeDictionary的findKey
