在Swift中,集合 Collections
是可变的容器,可以让你存储任意数量的值数据。
主要涉及的集合类型如下:
arrays //数组
dictionaries //字典
sets //集合
//Tip: 对应于,变量与常量。集合类型存在可变(Mutable)和不可变(immutable).
//对于集合类型的使用,往往涉及到值的遍历,在编程中要注意代码的时间复杂度及空间复杂度。
Arrays 数组
- Zero-indexed 数组的下标从0开始
- Order 数组是有序的
- Unrelated 数组中的元素非相关的,同一值可出现多次。
创建数组
let arrNumber:[Int] = [1, 2, 5, 4, 3]
//可以使用类型推断
let arrNumber = [1, 2, 3, 5, 4]
//创建一个空数组
var arrEmpty:[Int] = []
//使用系统库构建方法
let arrTemp = Array(repeating: 0, count: 5)
//这里设置了默认值来构建 [0, 0, 0, 0, 0]
访问数组元素
- 系统提供的便利方法
//eg.: 创建一个字符串类型的数组
var students = ["张三", "李四", "王五", "赵六"]
//对于许多方法的使用,可以去查阅系统库。这里简要说一些常用的。
//数组是否为空 Bool型
students.isEmpty
//数组元素个数
students.count
//便利方法,访问第一个元素。注意这是一个可选型数据,因为数组为空时,第一个元素也就是nil了。
students.first
print(students.first as Any)
/*
还记得 as 和 Any 么?
回顾一下,as 作为类型转换关键字。
Any 是Swift中任意类型都必须遵守的协议,换句话说也就是一个基类了。
所以,这里的转换流向是 从派生类(String?) -> 基类(Any)
作用是:阻止编译器产生警告
*/
- 下标方法
//subscript syntax 语法
/*
通过下标取得的元素并不是一个可选型!!!
所以在使用前,应该检查数组是否为空以及下标合法性。否则,会崩溃~~~
*/
var firstStudent = students[0]
Tip: 这里说明,下标语法是通过协议实现的。类、结构体等等类型都可以实现该协议,以提供下标方法。具体协议,后续补充。
数组切片
/*
将区间的概念结合到下标语法中,我们可以很容易的制作数组切片。
复习一下区间的语法:
闭合区间
1...6
半开区间
1..<6
*/
//取得数组切片
eg.:
let arrSlice = students[1...2]
/*
result: ["李四", "王五"]
需要特别注意的是,取得的切片数组并不是一个独立于原数组在外的数组。该方法,还是共享原数组的内存包括下标。
所以,如果你使用如下语句是会报错的。
arrSlice[0] //error
*/
//如果希望得到一个新的数组 可以用构造方法
let arrSlice2 = Array(students[1...2])
arrSlice2[0] //ok
数组操作
- 是否包含某一元素
students.contains("张三") //bool 类型
- 元素追加
//不说的话一定会有人忘记,数组是 mutable 类型才可以 即 var 类型。
students.append("李五")
//和 String 类似有一个系统实现的便利方法
students += ["NSaylor", "YourName"]
- 元素插入
//注意 下标不要超出当前范围
students.insert("老司机", at: 0)
students.insert("Jim", at: 100) //Error
- 元素移除
/*
便利的方法,该方法返回被移除的元素
*/
var removerStudents = students.remvoeLast()
/*
使用下标移除,该方法返回被移除的元素
*/
removerStudents = students.remove(at: 2)
- 元素更新
//使用下标方法
students[0] = "Tom"
//结合闭合区间 (具体结果,动动手试试)
students[0...1] = ["Anna", "John", "Swift"]
- 元素移动
//先移除,再插入
let john = students.remove(at: 1)
students.insert(john, at: 0)
//便利方法 直接传入下标即可
students.swapAt(0, 1)
/*
还有很多时候,需要对数组进行排序。
以后会经常遇到这个问题,可以使用闭包来赋予一定的排序规则。之后会完善,先有个概念。
*/
students.sort()
- 数组遍历
let ages = [18, 50, 34, 23, 24]
//快速遍历方法 for-in
for age in ages {
print(age)
}
//使用元组的快速 遍历方法 (index, element)->(下标,元素)
for (index, age) in ages.enumerated() {
print("index:\(index) -> element: \(age)")
}
Dictionaries 字典
- 字典基于键值对(key-value)这种映射关系来表示数据组织形式的
- 键值具有唯一性
- 键、值的类型必须是单一的,没有混搭的风格
- 字典是无序的
- 键必须满足哈希特性
创建字典
//手动创建
var namesAndAges = ["Bob": 20, "Tom": 12, "Jim": 15]
//创建空字典
namesAndAges = [:] //未指定键值类型
var dicEmpty: [String: Int] = [:] //指定了键值类型
dicEmpty.reserveCapacity(10) //指定字典容量,可以提供性能。在你确定的时候这样做!!!
访问字典内容
- 使用下标语法
namesAndAges["Bob"]
// Optional(20) 注意这是可选型
//使用不存在的键,会安全的返回nil
namesAndAges["Swift"] //nil
- 使用属性和方法
//判断字典是否为空
namesAndAges.isEmpty // bool 类型
//字典键值对数
namesAndAges.count //等同于当前容量
修改字典
- 增加键值对
- 更新内容
namesAndAges.updateValue(17, forKey:"mingming")
//更加便捷的方式
namesAndAges["zhangsan"] = 23
- 移除键值对
namesAndAges.removeValue(forKey:"Bob")
//便捷方式
namesAndAges["Bob"] = nil
/*
Tip:如果字典中值是可选型(optional)类型,手动置为nil.的方式仍然会从字典中移除该键值对。
如果想保留该键值对,但又想将值置为nil.
只能通过 `updateValue` 方法。
*/
- 遍历
//字典可以拆分为 键数组、值数组
//遍历键
for name in namesAndAges.keys {
print("\(name),", terminator: "")
}
//Tip: 注意 terminator: "", 这里是指定输出结尾方式。默认为换行、
//元组方式
for (name, age) in namesAndAges {
print("name:\(name) - age:\(age)")
}
//Tip: 回想一下数组的对应方式,不难俩想到数组是字典的一种特殊形式。
Hashable
在Swift中,String 、Int 、Double 、Bool 、etc 是具有哈希特性的。
Swift 字典中的键必须满足哈希特性,否则编译会报错。
这是保证唯一性的手段!!!
//可以查看对应的哈希值 eg.:
print(1.hashValue)
print("swift".hashValue)
//etc...
Sets 集合
- 集合存储的数据类型是单一的
- 集合是无序的
- 集合中的任意值是唯一的
创建集合
//声明语法
let setTemp: Set<Int>
//集合并没有自己的创建方式,可以通过数组来生成.
let arrTemp = [1, 2, 3, 3, 1]
var setNumber: Set<Int> = [1, 2, 3, 3, 4]
//Tip: 注意,这里为什么没有直接把数组直接赋值给集合呢???
//因为Swift是类型安全的,不同类型间是不能够自动转换的。
setNumber = arrTemp //Error [Int] -> Set<Int>
//打印集合数据
print(setNumber) // [1, 2, 3, 4] 少了一个3
/*
有疑惑的话,看下集合的特性。
所以,这里可以把集合看做是经过排重处理(自动行为),且无序的特殊数组。
*/
访问集合元素
//因为是无序的,所以并没有下标方法
//判断集合中是否包含值 返回值bool类型
setNumber.contains(1) // true
setNumber.contains(100) // false
集合元素操作
- 增加元素
setNumber.insert(6)
- 移除元素
//如果存在,则返回被移除的元素。否则返回 nil
let removedValue = setNumber.remove(1)