集合类型

目录

简介

Swift 提供了三种主要的集合类型, 即数组、集合和字典, 用于存储值的集合。

数组是值的有序集合。 集合是唯一值的无序集合。 字典是键值关联的无序集合。

Swift 中的数组、集合和字典总是明确它们可以存储的值和键的类型。这意味着无法在集合中插入错误类型的值, 也意味着可以确定从集合中检索的值的类型。

集合可变性

如果创建一个数组、集合或字典, 将其赋值给一个变量, 那么创建的集合将是可变的。 这意味着在创建集合后,可以通过添加、删除或更改集合中的项目来更改(或突变)集合。

如果将数组、集合或字典赋值给常量,则该集合是不可变的,其大小和内容都无法更改。

如果明确不需要更改集合, 最好的做法就是创建不可变集合。 这样做的好处是让编译器优化集合性能。

数组

数组以有序列表的形式存储相同类型的值。同一个值可以多次出现在数组的不同位置。

创建空数组

// 使用初始化语法创建特定类型的空数组
// 变量名后面加:[数据类型] = []
// []就是空数组的字面量

var ages: [Int] = []
print(ages) // []

创建有默认值的数组

数组类型有 Array 初始化器, 用于创建具有一定大小的数组, 并且将所有值设置为相同的默认值。

// Array初始化器, repeating后面就是默认值, count后面数字表示有几个值。
var ages = Array(repeating: 18, count: 5)
print(ages) // [18, 18, 18, 18, 18]

将已有数组相加创建新数组

使用加法运算符 + 可以将两个类型兼容的数组相加, 创建一个新数组。

let someNames = Array(repeating: "hzclog", count: 3)
print(someNames) // ["hzclog", "hzclog", "hzclog"]

let anotherNames = Array(repeating: "swift", count: 5)
print(anotherNames) // ["swift", "swift", "swift", "swift", "swift"]

let totalNames = someNames + anotherNames
print(totalNames) // ["hzclog", "hzclog", "hzclog", "swift", "swift", "swift", "swift", "swift"]

使用数组字面量创建数组

这是一种将一个或多个值写成数组集合的速记方法。

数组字面形式是一个值列表, 用 , 分隔, 周围使用方括号包围。

// 初始化时,数组方括号中直接写入值,每个值之间的,不要忘记
let names: [String] = ["陶喆", "王力宏", "周杰伦"]
print(names) // ["陶喆", "王力宏", "周杰伦"]

// 得益于swift类型推断,我们一般去掉类型也可以
let anotherNames = ["林俊杰", "方大同"]
print(anotherNames) // ["林俊杰", "方大同"]

访问和修改数组

count 属性获取数组里面值的数量。

let names: [String] = ["陶喆", "王力宏", "周杰伦"]
print(names.count) // 3

isEmpty 属性获取数组是否为空的布尔值。

let names: [String] = ["陶喆", "王力宏", "周杰伦"]
print(names.isEmpty) // false

append 方法在数组的末尾追加新的元素。

var products = ["apple", "banana"]
print(products) // ["apple", "banana"]

products.append("pear")
print(products) // ["apple", "banana", "pear"]

+= 运算符也可以用于追加一个或多个类型兼容的数组

var products = ["apple", "banana"]
print(products) // ["apple", "banana"]

products += ["pear", "watermelon"]
print(products) // ["apple", "banana", "pear", "watermelon"]

数组[下标] 的方式可以从数组读取指定位置的值。 与字符串索引不同, 使用数字就可以了。

从左到右, 从0开始, 最后一个位置显然就是数组的个数 - 1。

let ages = [18, 22, 20, 19]
print(ages[0]) // 18
print(ages[3]) // 19

给数组指定位置赋值的话,就是更新数组了。

var ages = [18, 22, 20, 19]
print(ages) // [18, 22, 20, 19]

ages[1] = 30
print(ages) // [18, 30, 20, 19]

// 也可以使用范围一次性更改一批
let range = 1...2
// 将位置1和2的元素换成一个110
ages[range] = [110]
print(ages) // [18, 110, 19]

insert(_:at:) 方法可以在指定位置插入元素。

var numbers = [10, 20, 30]
numbers.insert(40, at: 1) // 索引1的位置插入40
print(numbers) // [10, 40, 20, 30]

remove(at:) 方法可以移除并返回指定位置的元素。

var numbers = [10, 20, 30]
let removedItem = numbers.remove(at: 2) // 移除索引2的值
print(numbers) // [10, 20]
print(removedItem) // 30
⚠️

尝试访问或者修改数组时, 一定要注意索引的边界值。 因为一旦越界, 就会导致运行错误。

removeLast() 方法可以移除并返回数组的最后一项。

var numbers = [10, 20, 30, 40]
let removedItem = numbers.removeLast() // 移除最后一项
print(numbers) // [10, 20, 30]
print(removedItem) // 40

集合

集合将同一类型的不同值, 存储在一个集合中, 没有顺序。

如果值的顺序不重要, 或者要确保每个值只出现一次, 可以使用集合。

可散列值

只有可散列的数据类型, 才可以放在集合中。 即该类型必须提供一种计算散列值的方法。

Swift所有的基本类型(String, Int, Double,Bool)默认都是可散列的。 所以可以直接放在集合中。

如果想使用自定义类型作为集合的值, 必须让它实现Hashable协议。

类型语法

Swift集合类型写法是 Set<Element>, 其中Element就是集合存储的类型。

创建空集合

使用初始化语法创建空集合。

// 根据初始化器尖括号的类型,numbers变量被推断为Set<Int>
var numbers = Set<Int>()
print(numbers) // []

使用字面量创建集合

可以使用字面量初始化集合,这是一种将值写入集合的快捷方式。

var numbers: Set<Int> = [1, 2, 3]
print(numbers) // [2, 3, 1] 这里顺序不是固定的,可以多次运行看看

// 当然可以简短一点。集合类型声明必须保留,元素类型可以省略
var anotherNumbers: Set = [4, 5, 6]
print(anotherNumbers) // [4, 6, 5] 顺序同样是乱的

访问和修改集合

count 属性获得集合中的元素数量。

let brands: Set = ["apple", "xiaomi", "sunsumg"]
print(brands.count) // 3

isEmpty 属性判断集合是否为空。

let brands: Set = ["apple", "xiaomi", "sunsumg"]
print(brands.isEmpty) // false

insert(_:) 方法插入新的元素。

var brands: Set = ["apple", "xiaomi", "sunsumg"]
brands.insert("huawei")
print(brands) // ["apple", "xiaomi", "huawei", "sunsumg"]

remove(_:) 方法从集合中移除并返回指定元素。

var brands: Set = ["apple", "xiaomi", "sunsumg"]
let removedItem = brands.remove("sunsumg")
print(brands) // ["apple", "xiaomi"]
print(removedItem) // Optional("sunsumg")

contains(_:) 检查集合中是否包含指定元素。

var brands: Set = ["apple", "xiaomi", "sunsumg"]
print(brands.contains("huawei")) // false

集合运算

如果你对数学课程还存有记忆的话, 应该能想起数学中也存在集合的概念。 两个集合可以合并, 可以确定公共值, 可以确定是否包含或者不包含相同的值等等。

Swift中的集合支持这样常见的运算。

交集

intersection(_:) 方法创建一个新集合,返回两个集合都存在的值。

let number1: Set = [1, 2, 3, 4, 5]
let number2: Set = [1, 3, 5, 7, 9]
print(number1.intersection(number2)) // [1, 3, 5]

并集

union(_:) 方法创建一个新集合,包含两个集合所有的值。

let number1: Set = [1, 2, 3, 4, 5]
let number2: Set = [1, 3, 5, 7, 9]
print(number1.union(number2)) // [9, 4, 2, 5, 1, 7, 3]

差集

subtracting(_:) 创建一个新集合,其中的值不在指定集合中。

比如 a.subtracting(b), 就是a集合有, b集合没有的值。

let number1: Set = [1, 2, 3, 4, 5]
let number2: Set = [1, 3, 5, 7, 9]
print(number1.subtracting(number2)) // [4, 2]
print(number2.subtracting(number1)) // [9, 7]

对称差集

symmetricDifference(_:) 创建新集合,里面的值只在其中一个集合中出现过。 相当于 并集 - 交集

let number1: Set = [1, 2, 3, 4, 5]
let number2: Set = [1, 3, 5, 7, 9]
print(number1.symmetricDifference(number2)) // [9, 4, 7, 2]

成员与相等关系

相等

== 运算符判断两个集合是否包含所有相同的值。

let number1: Set = [1, 3, 5]
let number2: Set = [1, 5, 3]
print(number1 == number2) // true

子集

isSubset(of:) 方法确定当前集合的值是否都在指定集合中。

let number1: Set = [1, 3, 5]
let number2: Set = [1, 5, 3, 7, 9]
print(number1.isSubset(of: number2)) // true

超集

isSuperset(of:) 方法确定当前集合是否包含指定集合所有的值。

let number1: Set = [1, 3, 5]
let number2: Set = [1, 5, 3, 7, 9]
print(number1.isSuperset(of: number2)) // false
print(number2.isSuperset(of: number1)) // true

严格子集或超集

isStrictSubset(of:)isStrictSuperset(of:) 确定集合是否是指定集合的子集或超集,但不能等于指定集合。

let number1: Set = [1, 3, 5]
let number2: Set = [1, 5, 3, 7, 9]
let number3: Set = [5, 3, 1]
print(number1.isStrictSubset(of: number2)) // true
print(number1.isStrictSubset(of: number3)) // false
print(number2.isStrictSuperset(of: number3)) // true

无共同值

isDisjoint(with:) 方法确定两个集合是否没有共同值。

let number1: Set = [2, 4, 6, 8, 10]
let number2: Set = [1, 5, 3, 7, 9]
let number3: Set = [1, 2, 4, 6]
print(number1.isDisjoint(with: number2)) // true
print(number1.isDisjoint(with: number3)) // false

字典

字典以集合的形式, 存储同一类型的键和同一类型的值之间的关联, 没有顺序。

键就是值在字典中的标识符, 每个值都与一个唯一的键相关联。

速记语法

字典类型写作 Dictionary<Key, Value>, 其中Key是键的类型, Value是值的类型。

也可以使用速记写法 [Key: Value]

⚠️

字典键的类型必须符合Hashable协议,就像集合的值一样。

创建空字典

使用初始化语法创建特定类型的空字典。

// users是[Int: String]类型的空字典,键是Int,值是String类型
var users: [Int: String] = [:]
print(users) // [:]

使用字面量创建字典

使用字面量初始化字典。 键值对是键和值的组合, 每个键值对中的键和值使用:分隔, 键值对使用列表的形式书写, 用逗号分隔, 并且使用方括号包围。

var userAges: [String: Int] = ["王力宏": 47, "陶喆": 54, "周杰伦": 46]
print(userAges) // ["陶喆": 54, "王力宏": 47, "周杰伦": 46]

// 字面量形式已经给出了类型,所以可以简短些
var anotherUserAges = ["王力宏": 47, "陶喆": 54, "周杰伦": 46]
print(anotherUserAges) // ["周杰伦": 46, "王力宏": 47, "陶喆": 54]

访问和修改字典

count 属性获得字典键值对的数量。

var productPrice = ["apple": 5.0, "banana": 2.5, "watermelon": 2.0]
print(productPrice.count) // 3

isEmpty 属性返回字典是否为空的布尔值。

var productPrice = ["apple": 5.0, "banana": 2.5, "watermelon": 2.0]
print(productPrice.isEmpty) // false

字典[键] 可以获取字典指定键的值。

var productPrice = ["apple": 5.0, "banana": 2.5, "watermelon": 2.0]
print(productPrice["banana"]) // Optional(2.5)
print(productPrice["pear"]) // nil

字典[键] = 值 语法用于添加或者更新键值对。

var productPrice = ["apple": 5.0, "banana": 2.5, "watermelon": 2.0]
productPrice["pear"] = 1.5
print(productPrice) // ["apple": 5.0, "pear": 1.5, "banana": 2.5, "watermelon": 2.0]
productPrice["apple"] = 7.5
print(productPrice) // ["apple": 7.5, "pear": 1.5, "banana": 2.5, "watermelon": 2.0]

字典[键] = nil 语法用于删除键值对。

var productPrice = ["apple": 5.0, "banana": 2.5, "watermelon": 2.0]
print(productPrice) // ["watermelon": 2.0, "banana": 2.5, "apple": 5.0]
productPrice["apple"] = nil
print(productPrice) // ["banana": 2.5, "watermelon": 2.0]

下一章

通过本篇文章, 我们主要是了解集合类型: 数组、 集合和字典的使用。 掌握这些集合类型的操作非常关键。

下一章中,我们来聊聊Swift中的控制流。