Swift3.1_集合类型
集合类型的可变性
集合类型的可变性取决于声明为let
还是var
,let
声明的集合类型是不可变的,它的大小和内容都不能被改变。var
声明的集合类型是可变的,这意味着我们可以在创建之后添加更多或移除已存在的数据项,或者改变集合中的数据项。
集合类型是值类型
Swift
语言提供数组Array
、集合Set
和字典Dictionarie
三种基本的集合类型用来存储集合数据。他们的都是struct
类,所以是值类型。
public struct Array<Element> : RandomAccessCollection, MutableCollection {
...
}
public struct Set<Element> : SetAlgebra, Hashable, Collection, ExpressibleByArrayLiteral where Element : Hashable {
...
}
public struct Dictionary<Key, Value> : Collection, ExpressibleByDictionaryLiteral where Key : Hashable {
...
}
数组 Array
构造
var someDoubles = [double]() // double 类型可变数组
var someStrings: [String] = [] // String 类型的可变数组
var threeInts = Array(repeating: 0, count: 3) // 默认值都是0 长度是3的可变数组
let cars = ["Benz", "BMW", "Porsche"] // 字面量构造 不可变数组
数组相加
我们可以使用加法操作符+
来组合两种已存在的相同类型数组。新数组的数据类型会被从两个数组的数据类型中推断出来:
let array1 = [1, 2, 3]
let array2 = [4, 5]
var newArray = array1 + array2 // [1, 2, 3, 4, 5]
访问数组
数组长度
newArray.count // 5
是否为空
newArray.isEmpty // false
包含
newArray.contains(3) // true
newArray.contains(6) // false
读取
let num = newArray[1] // 2
修改数组
增加
- 从尾部追加
newArray.append(6) // [1, 2, 3, 4, 5, 6]
newArray.append(contentsOf: [7, 8]) // [1, 2, 3, 4, 5, 6, 7, 8]
- 插入
newArray.insert(0, at: 0)
// [0, 1, 2, 3, 4, 5, 6, 7, 8]
newArray.insert(contentsOf: [9, 10], at: 2)
// [0, 1, 9, 10, 2, 3, 4, 5, 6, 7, 8]
替换
newArray[0] = 100
// [100, 1, 9, 10, 2, 3, 4, 5, 6, 7, 8]
newArray.replaceSubrange(2...3, with: [20, 30])
// [0, 1, 20, 30, 2, 3, 4, 5, 6, 7, 8]
删除
newArray.removeFirst()
// [1, 20, 30, 2, 3, 4, 5, 6, 7, 8]
newArray.removeLast()
// [1, 20, 30, 2, 3, 4, 5, 6, 7]
newArray.remove(at: 2)
// [1, 20, 2, 3, 4, 5, 6, 7]
newArray.removeSubrange(1..<4)
// [1, 4, 5, 6, 7]
newArray.removeAll()
// []
遍历
使用for-in
循环来遍历所有数组中的数据项:
let array = [1, 2, 3, 4]
for item in array {
print(item)
}
// 1
// 2
// 3
// 4
使用for-in
循环来遍历所有数组中的下标和数据项:
for (index, item) in array.enumerated() {
print("\(index) : \(item)")
}
// 0 : 1
// 1 : 2
// 2 : 3
// 3 : 4
排序
原数组排序
- 升序
// 可变数组才能原数组排序,改变的是本身
var numbers = [8, 4, 5, 2, 1]
numbers.sort() // numbers : [1, 2, 4, 5, 8]
- 降序
numbers.sort(by: >)
// [8, 5, 4, 2, 1]
排序生成新数组
- 升序
// 生成新数组,原数组可以是不可变
let numbers = [8, 4, 5, 2, 1]
let ascendingNumbers = numbers.sorted()
// [1, 2, 4, 5, 8]
// 等价
let ascendingNumbers = numbers.sorted(by: <)
- 降序
let descendingNumbers = numbers.sorted(by: >)
数组去重复
可以利用Set
或者Dictinary
的不重复性:
let array = [3, 5, 9, 6, 1, 5, 3]
let aSet: Set = Set(array);
let newArray = set.sorted() // [1, 3, 5, 6, 9]
集合 Set
集合Set
用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。
集合类型的哈希值
一个类型为了存储在集合中,该类型必须是可哈希化的,也就是说,该类型必须提供一个方法来计算它的哈希值。一个哈希值是Int
类型的,相等的对象哈希值必须相同,比如a==b
,因此必须a.hashValue == b.hashValue
。
Swift
的所有基本类型(比如String
,Int
,Double
和Bool
)默认都是可哈希化的,可以作为集合的值的类型或者字典的键的类型。没有关联值的枚举成员值默认也是可哈希化的。
注意:
你可以使用你自定义的类型作为集合的值的类型或者是字典的键的类型,但你需要使你的自定义类型符合 Swift 标准库中的Hashable协议。符合Hashable协议的类型需要提供一个类型为Int的可读属性hashValue。由类型的hashValue属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。因为Hashable协议符合Equatable协议,所以遵循该协议的类型也必须提供一个"是否相等"运算符(==)的实现。这个Equatable协议要求任何符合==实现的实例间都是一种相等的关系。也就是说,对于a,b,c三个值来说,==的实现必须满足下面三种情况:
a == a(自反性)
a == b意味着b == a(对称性)
a == b && b == c意味着a == c(传递性)
构造
var letters = Set<Int>() // 空集合
var cars: Set<String> = ["Benz", "BMW", "Ferrari"] // 字面量构造
var cars: Set = ["Benz", "BMW", "Ferrari"] // 简化字面量构造
访问集合
集合长度
var set: Set = [1, 2, 3]
set.count // 3
是否为空
set.isEmpty // false
包含
set.contains(4) // false
set.contains(3) // true
修改集合
添加
set.insert(5) // 添加 5
删除
set.remove(2) // 删除特定值 2
set.removeAll() // 删除全部
遍历
通过for-in
遍历集合
let cars: Set = ["Benz", "BMW", "Ferrari"]
for item in cars {
print(item)
}
// Ferrari
// BMW
// Benz
Swift
的Set
类型没有确定的顺序,为了按照特定顺序来遍历一个Set
中的值可以使用sorted()
方法,它将返回一个有序数组,
for item in cars.sorted() {
print(item)
}
// BMW
// Benz
// Ferrari
排序
Swift
的Set
类型是无序集合类型。为了以特定的顺序遍历Set
的值,可以使用sorted()
方法。
集合操作
你可以高效地完成Set
的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。
基本集合操作
let set1: Set = [1, 3, 5, 7]
let set2: Set = [0, 2, 4, 6]
let set3: Set = [2, 3, 6, 7]
// 两个集合合并成新的集合
let uniSet = set1.union(set2) // [2, 4, 5, 7, 6, 3, 1, 0]
// 两个集合的交集生成新集合
let intSet12 = set1.intersection(set2) // []
let intSet13 = set1.intersection(set3) // [7, 3]
// 两个集合的差集生成新集合
let symSet = set1.symmetricDifference(set3) // [5, 6, 2, 1]
// 集合1的子集却不是集合2的子集
let subSet = set1.subtracting(set3) // [5, 1]
集合成员关系判断
同样的可以通过Set
方法判断两个几个的关系:
// 判断两个集合是否包含相同的值
set1 == set2 // false
// 判断一个集合中的值是否也被包含在另外一个集合中
set1.isSubset(of: set2) // false
subSet.isSubset(of: set1) // true
// 方法来判断一个集合中包含另一个集合中所有的值
set1.isSuperset(of: set2) // false
set1.isSuperset(of: subSet) // true
// 判断一个集合是否是另外一个集合的子集并且不相等
subSet.isStrictSubset(of: set1) // ture
// 判断一个集合是否是另外一个集合的父集并且不相等
set1.isStrictSuperset(of: subSet) // ture
// 判断两个集合是否不含有相同的值(是否没有交集)
set1.isDisjoint(with: set2) // true
set1.isDisjoint(with: set3) // false
字典 Dictionary
字典是一种存储多个相同类型的值的容器。每个值value
都关联唯一的键key
,键作为字典中的这个值数据的标识符。和数组中的数据项不同,字典中的数据项并没有具体顺序。
构造
var nameOfID = [Int: String]() // 空字典
var dict: [Int: String] = [1: "one", 2: "two", 3: "three"] // 字面量构造
var dict = [1: "one", 2: "two", 3: "three"] // 简化构造
访问字典
和Array
、Set
一样字典Dictionary
也可以访问长度、是否包含、是否为空:
dict.count // 3
dict.isEmpty // false
dict.contains(where: { $0 == 1 && $1 == "one" }) // ture
dict.keys.contains(where: { $0 == 1 }) // ture
dict.values.contains(where: { $0 == "Two"}) // false
修改字典
增加和修改
// 有对用key就修改,没有就增加
dict.updateValue("four", forKey: 4)
// 修改
dict[1] = "One" // [2: "two", 3: "three", 1: "One", 4: "four"]
删除
dict.removeValue(forKey: 1) // [2: "two", 3: "three", 4: "four"]
dict.removeAll() // 删除全部
遍历
我们可以使用for-in循环来遍历某个字典中的键值对。每一个字典中的数据项都以(key, value)
元组形式返回,并且我们可以使用临时常量或者变量来分解这些元组:
for (key, value) in dict {
print("\(key) : \(value)")
}
// 2 : two
// 3 : three
// 4 : four
通过访问keys
、values
:
for key in dict.keys {
print(key)
}
// 2
// 3
// 4
for value in dict.values {
print(value)
}
// two
// three
// four
排序
Swift
的字典类型是无序集合类型。为了以特定的顺序遍历字典的键或值,可以对字典的keys
或values
属性使用sorted()
方法。