第4章:集合类型
Swift提供三种主要的集合类型 ,称为数组,集合和字典; 数组是有序的值集合,集合是唯一值的无序集合,字典是键值关联的无序集合。Swift中的数组,集合和字典总是清楚它们可以存储的值和键的类型。 这意味着您不能错误地将错误类型的值插入到集合中。 这也意味着您可以对从集合中检索的值的类型充满信心。
如果创建数组,集合或字典,并将其分配给变量,则创建的集合将是可变的 。 这意味着您可以通过添加,删除或更改集合中的项目来更改(或更改)集合。 如果将数组,集合或字典分配给常量,则该集合是不可变的 ,并且其大小和内容不能更改。
4.1 数组
Swift数组的类型完全写为Array<Element> ,其中Element是允许数组存储的值的类型。 您还可以以简写形式将数组类型写为[Element] 。 虽然这两种形式在功能上是相同的,但是简写形式是首选的。
// 创建空数组
var someInts = [ Int ]()
print ( "someInts is of type [Int] with \( someInts . count ) items." )
// 创建空数组
var anotherInts = Array<Int>()
print ( "anotherInts is of type [Int] with \( anotherInts . count ) items." )
// 创建具有3个元素且都为0.0的数组
var threeDoubles = Array ( repeating : 0.0 , count : 3 )
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
// 创建具有3个元素且都为2.5的数组
var anotherThreeDoubles = Array ( repeating : 2.5 , count : 3 )
// anotherThreeDoubles is of type [Double], and equals [2.5, 2.5, 2.5]
// 通过加号创建一个新的数组
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
// 创建一个字符串数组
var shoppingList : [ String ] = [ "Eggs" , "Milk" ]
// 通过swift编译器的类型推断来确定数组元素的类型为字符串
var shoppingList= [ "Eggs" , "Milk" ]
// 访问、修改数组
// 通过count属性获取数组元素个数
print("The shopping list contains \(shoppingList.count) items.")
// 通过isEmpty属性来获取数组是否为空
if shoppingList.isEmpty {
print("The shopping list is empty.")
} else {
print("The shopping list is not empty.")
}
// 通过append方法为数组追加元素
shoppingList.append("Flour")
// 通过+=方法为数组追加元素
shoppingList += [ "Baking Powder" ]
// 通过下标访问数组元素
// 数组下标是有效范围是[0,shoppingList.count - 1]
// 如果给定范围不在有效范围内,则触发运行时错误
var firstItem = shoppingList [ 0 ]
// 通过下标语法修改数组某元素的值
shoppingList[0] = "Six eggs"
// 通过范围运算符可以修改多个数组元素
shoppingList [ 4 ... 6 ] = [ "Bananas" , "Apples" ]
// 通过insert方法可在数组指定位置插入元素
shoppingList.insert("Maple Syrup", at: 0)
// 通过remove方法删除数组元素
let mapleSyrup = shoppingList . remove ( at : 0 )
// 方便的删除最后一个元素的方法
let apples = shoppingList.removeLast()
// 数组元素的迭代访问方法
// 普通迭代访问
for item in shoppingList {
print(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas
// 访问数组下标的迭代访问
for (index, value) in shoppingList.enumerated() {
print("Item \(index + 1): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas
4.2 集合
在swift中集合存储的元素必须是符合Hashable协议的,swift提供的所有类型都是符合该协议的。符合Hashable的类型的哈希值是Int类型,没有指定原始值的枚举类型也是可以存储在集合之中
。
注意
您可以使用自己的自定义类型作为集合的元素或者字典的键类型,只要该类型遵循Swift标准库中的Hashable
协议。 符合Hashable
协议的类型必须提供名为hashValue
的gettableInt
属性。 类型的hashValue
属性返回的值在同一程序的不同执行或不同程序中不需要相同。
因为Hashable
协议符合Equatable
,所以符合类型还必须提供equals运算符(==
)的实现。Equatable
协议要求==
任何符合实现都是等价关系。 也就是说,对于所有值a
,b
和c
,==
的实现必须满足以下三个条件:
a == a
(反身性)a == b
表示b == a
(对称性)a == b && b == c
意味着a == c
(及物性)
Swift集的类型写为Set<Element> ,其中Element是允许集存储的类型。 与数组不同,集合没有等效的简写形式。
// 创建空集合的语法,并通过count访问集合元素的个数
var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
// 使用数组语法创建集合
// 在以下的示例中,set关键字不可或缺,因为通过后面的数组语法不足以推断类型是集合类型
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
// 通过isEmpty方法判断数组是否为空
if favoriteGenres.isEmpty {
print("As far as music goes, I'm not picky.")
} else {
print("I have particular music preferences.")
}
// 通过insert方法向集合添加元素
favoriteGenres.insert("Jazz")
// 通过remove方法删除元素,如果没有该元素则返回nil
// removeAll方法可以删除所有元素
if let removedGenre = favoriteGenres.remove("Rock") {
print("\(removedGenre)? I'm over it.")
} else {
print("I never much cared for that.")
}
// 通过contains方法判断集合是否包含某元素
if favoriteGenres.contains("Funk") {
print("I get up on the good foot.")
} else {
print("It's too funky in here.")
}
// 迭代访问集合元素
for genre in favoriteGenres {
print("\(genre)")
}
// 此方法将调用元素的小于号运算符来确定顺序,并按照顺序输出
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
下面以集合a、b为示例,指出集合操作的结果,结果以深色标识。
image.png
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]
4.3 字典
Swift字典的类型完整地写为Dictionary<Key, Value> ,其中Key是可以用作字典键的Value的类型, Value是字典为这些键存储的值的类型;字典的key的类型必须符合Hashable协议;还可以将字典类型缩写为[Key: Value] 。
// 创建空字典
var namesOfIntegers = Dictionary<Int: String>()
var namesOfIntegers = [Int: String]()
// XYZ、DUB是键
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// 通过类型推断创建字典
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// 访问或修改字典
// 输出字典元素个数
print("The airports dictionary contains \(airports.count) items.")
// 判断字典是否为空
if airports.isEmpty {
print("The airports dictionary is empty.")
} else {
print("The airports dictionary is not empty.")
}
// 如果LHR指定的键不存在,则把此键与值添加到字典中
// 如果LHR指定的键存在,则把此键指定的值修改为London
// 以上通过下标的操作也可以通过updateValue(_:forKey:)方法完成
airports["LHR"] = "London"
// 通过removeValue方法删除指定元素
if let removedValue = airports.removeValue(forKey: "DUB") {
print("The removed airport's name is \(removedValue).")
} else {
print("The airports dictionary does not contain a value for DUB.")
}
// 迭代字典
// 访问所有的键与值
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
// YYZ: Toronto Pearson
// LHR: London Heathrow
// 只访问键
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}
// Airport code: YYZ
// Airport code: LHR
// 只访问值
for airportName in airports.values {
print("Airport name: \(airportName)")
}
// Airport name: Toronto Pearson
// Airport name: London Heathrow
// 获得键的数组
let airportCodes = [String](airports.keys)
// airportCodes is ["YYZ", "LHR"]
// 获得值的数组
let airportNames = [String](airports.values)
// airportNames is ["Toronto Pearson", "London Heathrow"]