集合類型
Swift 語(yǔ)言提供數(shù)組(Array)鬼雀、集合(Set)和字典(Dictionary)三種基本的集合類型用來(lái)存儲(chǔ)集合數(shù)據(jù)岂膳。數(shù)組是有序數(shù)據(jù)的集岖沛。集合是無(wú)序無(wú)重復(fù)數(shù)據(jù)的集钠怯。字典是無(wú)序的鍵值對(duì)的集找颓。
Swift 中的數(shù)組、集合和字典必須明確其中保存的鍵和值類型照捡,這樣就可以避免插入一個(gè)錯(cuò)誤數(shù)據(jù)類型的值。同理话侧,對(duì)于獲取到的值你也可以放心栗精,其數(shù)據(jù)類型是確定的。
注意
Swift 的數(shù)組瞻鹏、集合和字典類型被實(shí)現(xiàn)為泛型集合悲立。更多關(guān)于泛型類型和集合,參見 泛型 章節(jié)新博。
集合的可變性
如果創(chuàng)建一個(gè)數(shù)組薪夕、集合或字典并且把它分配成一個(gè)變量,這個(gè)集合將會(huì)是可變的赫悄。這意味著可以在創(chuàng)建之后添加原献、修改或者刪除數(shù)據(jù)項(xiàng)馏慨。如果把數(shù)組、集合或字典分配成常量姑隅,那么它就是不可變的写隶,它的大小和內(nèi)容都不能被改變。
注意
在不需要改變集合的時(shí)候創(chuàng)建不可變集合是很好的實(shí)踐讲仰。這樣做便于你理解自己的代碼慕趴,也能讓 Swift 編譯器優(yōu)化集合的性能。
數(shù)組(Arrays)
數(shù)組使用有序列表存儲(chǔ)同一類型的多個(gè)值鄙陡。相同的值可以多次出現(xiàn)在一個(gè)數(shù)組的不同位置中冕房。
注意
Swift 的
Array
類型被橋接到 Foundation 中的NSArray
類。更多關(guān)于在 Foundation 和 Cocoa 中使用
Array
的信息趁矾,參見 Bridging Between Array and NSArray耙册。
數(shù)組的簡(jiǎn)單語(yǔ)法
Swift 中數(shù)組的完整寫法為 Array<Element>
,其中 Element
是這個(gè)數(shù)組中唯一允許存在的數(shù)據(jù)類型愈魏。也可以使用像 [Element]
這樣的簡(jiǎn)單語(yǔ)法觅玻。盡管兩種形式在功能上是一樣的,但是推薦較短的那種培漏,而且在本文中都會(huì)使用這種形式來(lái)使用數(shù)組溪厘。
創(chuàng)建一個(gè)空數(shù)組
你可以使用構(gòu)造語(yǔ)法來(lái)創(chuàng)建一個(gè)由特定數(shù)據(jù)類型構(gòu)成的空數(shù)組:
var someInts: [Int] = []
print("someInts is of type [Int] with \(someInts.count) items.")
// 打印“someInts is of type [Int] with 0 items.”
注意,通過(guò)構(gòu)造函數(shù)的類型牌柄,someInts
的值類型被推斷為 [Int]
畸悬。
或者,如果代碼上下文中已經(jīng)提供了類型信息珊佣,例如一個(gè)函數(shù)參數(shù)或者一個(gè)已經(jīng)定義好類型的常量或者變量蹋宦,你可以使用空數(shù)組語(yǔ)句創(chuàng)建一個(gè)空數(shù)組,它的寫法很簡(jiǎn)單:[]
(一對(duì)空方括號(hào)):
someInts.append(3)
// someInts 現(xiàn)在包含一個(gè) Int 值
someInts = []
// someInts 現(xiàn)在是空數(shù)組咒锻,但是仍然是 [Int] 類型的冷冗。
創(chuàng)建一個(gè)帶有默認(rèn)值的數(shù)組
Swift 中的 Array
類型還提供一個(gè)可以創(chuàng)建特定大小并且所有數(shù)據(jù)都被默認(rèn)的構(gòu)造方法』笸В可以把準(zhǔn)備加入新數(shù)組的數(shù)據(jù)項(xiàng)數(shù)量(count
)和適當(dāng)類型的初始值(repeating
)傳入數(shù)組構(gòu)造函數(shù):
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles 是一種 [Double] 數(shù)組蒿辙,等價(jià)于 [0.0, 0.0, 0.0]
通過(guò)兩個(gè)數(shù)組相加創(chuàng)建一個(gè)數(shù)組
你可以使用加法操作符(+
)來(lái)組合兩個(gè)已存在的相同類型數(shù)組。新數(shù)組的數(shù)據(jù)類型會(huì)從兩個(gè)數(shù)組的數(shù)據(jù)類型中推斷出來(lái):
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles 被推斷為 [Double]滨巴,等價(jià)于 [2.5, 2.5, 2.5]
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles 被推斷為 [Double]思灌,等價(jià)于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
用數(shù)組字面量構(gòu)造數(shù)組
你可以使用數(shù)組字面量來(lái)進(jìn)行數(shù)組構(gòu)造,這是一種用一個(gè)或者多個(gè)數(shù)值構(gòu)造數(shù)組的簡(jiǎn)單方法恭取。數(shù)組字面量是一系列由逗號(hào)分割并由方括號(hào)包含的數(shù)值:
[value 1, value 2, value 3]
泰偿。
下面這個(gè)例子創(chuàng)建了一個(gè)叫做 shoppingList
并且存儲(chǔ) String
的數(shù)組:
var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList 已經(jīng)被構(gòu)造并且擁有兩個(gè)初始項(xiàng)。
shoppingList
變量被聲明為“字符串值類型的數(shù)組“蜈垮,記作 [String]
耗跛。因?yàn)檫@個(gè)數(shù)組被規(guī)定只有 String
一種數(shù)據(jù)結(jié)構(gòu)裕照,所以只有 String
類型可以在其中被存取。在這里课兄,shoppingList
數(shù)組由兩個(gè) String
值("Eggs"
和 "Milk"
)構(gòu)造牍氛,并且由數(shù)組字面量定義。
注意
shoppingList
數(shù)組被聲明為變量(var
關(guān)鍵字創(chuàng)建)而不是常量(let
創(chuàng)建)是因?yàn)橹髸?huì)有更多的數(shù)據(jù)項(xiàng)被插入其中烟阐。
在這個(gè)例子中搬俊,字面量?jī)H僅包含兩個(gè) String
值。匹配了該數(shù)組的聲明(只能包含 String
的數(shù)組)蜒茄,所以可以將這個(gè)字面量的賦值過(guò)程看作用兩個(gè)初始項(xiàng)來(lái)構(gòu)造 shoppingList
的一種方式唉擂。
由于 Swift 的類型推斷機(jī)制,當(dāng)你用字面量構(gòu)造擁有相同類型值數(shù)組的時(shí)候檀葛,不必把數(shù)組的類型定義清楚玩祟。shoppingList
的構(gòu)造也可以這樣寫:
var shoppingList = ["Eggs", "Milk"]
因?yàn)樗袛?shù)組字面量中的值都是相同的類型,Swift 可以推斷出 [String]
是 shoppingList
中變量的正確類型屿聋。
訪問(wèn)和修改數(shù)組
你可以通過(guò)數(shù)組的方法和屬性來(lái)訪問(wèn)和修改數(shù)組空扎,或者使用下標(biāo)語(yǔ)法。
可以使用數(shù)組的只讀屬性 count
來(lái)獲取數(shù)組中的數(shù)據(jù)項(xiàng)數(shù)量:
print("The shopping list contains \(shoppingList.count) items.")
// 輸出“The shopping list contains 2 items.”(這個(gè)數(shù)組有2個(gè)項(xiàng))
使用布爾屬性 isEmpty
作為一個(gè)縮寫形式去檢查 count
屬性是否為 0
:
if shoppingList.isEmpty {
print("The shopping list is empty.")
} else {
print("The shopping list is not empty.")
}
// 打印“The shopping list is not empty.”(shoppinglist 不是空的)
也可以使用 append(_:)
方法在數(shù)組后面添加新的數(shù)據(jù)項(xiàng):
shoppingList.append("Flour")
// shoppingList 現(xiàn)在有3個(gè)數(shù)據(jù)項(xiàng)润讥,似乎有人在攤煎餅
除此之外转锈,也可以使用加法賦值運(yùn)算符(+=
)直接將另一個(gè)相同類型數(shù)組中的數(shù)據(jù)添加到該數(shù)組后面:
shoppingList += ["Baking Powder"]
// shoppingList 現(xiàn)在有四項(xiàng)了
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList 現(xiàn)在有七項(xiàng)了
可以直接使用下標(biāo)語(yǔ)法來(lái)獲取數(shù)組中的數(shù)據(jù)項(xiàng),把所需要數(shù)據(jù)項(xiàng)的索引值直接放在數(shù)組名稱之后的方括號(hào)中:
var firstItem = shoppingList[0]
// 第一項(xiàng)是“Eggs”
注意
第一項(xiàng)在數(shù)組中的索引值是
0
而不是1
楚殿。 Swift 中的數(shù)組索引總是從零開始撮慨。
你也可以用下標(biāo)來(lái)改變某個(gè)有效索引值對(duì)應(yīng)的數(shù)據(jù)值:
shoppingList[0] = "Six eggs"
// 其中的第一項(xiàng)現(xiàn)在是“Six eggs”而不是“Eggs”
當(dāng)你使用下標(biāo)語(yǔ)法,所使用的下標(biāo)必須是有效的脆粥。例如砌溺,試圖通過(guò) shoppingList[shoppingList.count] = "Salt"
在數(shù)組的最后添加一項(xiàng),將產(chǎn)生一個(gè)運(yùn)行時(shí)錯(cuò)誤变隔。
還可以利用下標(biāo)來(lái)一次改變一系列數(shù)據(jù)值规伐,即使新數(shù)據(jù)和原有數(shù)據(jù)的數(shù)量是不一樣的。下面的例子把 "Chocolate Spread"
匣缘、"Cheese"
和 "Butter"
替換為 "Bananas"
和 "Apples"
:
shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList 現(xiàn)在有6項(xiàng)
通過(guò)調(diào)用數(shù)組的 insert(_:at:)
方法在某個(gè)指定索引值之前添加數(shù)據(jù)項(xiàng):
shoppingList.insert("Maple Syrup", at: 0)
// shoppingList 現(xiàn)在有7項(xiàng)
// 現(xiàn)在是這個(gè)列表中的第一項(xiàng)是“Maple Syrup”
這次 insert(_:at:)
方法調(diào)用把值為 "Maple Syrup"
的新數(shù)據(jù)項(xiàng)插入列表的最開始位置猖闪,并且使用 0
作為索引值。
類似的可以使用 remove(at:)
方法來(lái)移除數(shù)組中的某一項(xiàng)孵户。這個(gè)方法把數(shù)組在特定索引值中存儲(chǔ)的數(shù)據(jù)項(xiàng)移除并且返回這個(gè)被移除的數(shù)據(jù)項(xiàng)(不需要的時(shí)候就可以無(wú)視它):
let mapleSyrup = shoppingList.remove(at: 0)
// 索引值為0的數(shù)據(jù)項(xiàng)被移除
// shoppingList 現(xiàn)在只有6項(xiàng)萧朝,而且不包括 Maple Syrup
// mapleSyrup 常量的值等于被移除數(shù)據(jù)項(xiàng)“Maple Syrup”
注意
如果你試圖通過(guò)越界索引來(lái)執(zhí)行訪問(wèn)或者修改數(shù)據(jù)的操作岔留,會(huì)引發(fā)一個(gè)運(yùn)行時(shí)錯(cuò)誤夏哭。此時(shí)可以使用索引值和數(shù)組的
count
屬性進(jìn)行比較來(lái)在使用該索引之前檢驗(yàn)其是否有效。除了當(dāng)count
等于 0 時(shí)(說(shuō)明這是個(gè)空數(shù)組)献联,最大索引值一直是count - 1
竖配,因?yàn)閿?shù)組都是零起索引何址。
數(shù)據(jù)項(xiàng)被移除后數(shù)組中的空出項(xiàng)會(huì)被自動(dòng)填補(bǔ),所以現(xiàn)在索引值為 0
的數(shù)據(jù)項(xiàng)的值再次等于 "Six eggs"
:
firstItem = shoppingList[0]
// firstItem 現(xiàn)在等于“Six eggs”
如果你只想把數(shù)組中的最后一項(xiàng)移除进胯,可以使用 removeLast()
方法而不是 remove(at:)
方法來(lái)避免需要獲取數(shù)組的 count
屬性用爪。就像后者一樣,前者也會(huì)返回被移除的數(shù)據(jù)項(xiàng):
let apples = shoppingList.removeLast()
// 數(shù)組的最后一項(xiàng)被移除了
// shoppingList 現(xiàn)在只有5項(xiàng)胁镐,不包括 Apples
// apples 常量的值現(xiàn)在等于字符串“Apples”
數(shù)組的遍歷
你可以使用 for-in
循環(huán)來(lái)遍歷數(shù)組中所有的數(shù)據(jù)項(xiàng):
for item in shoppingList {
print(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas
如果同時(shí)需要每個(gè)數(shù)據(jù)項(xiàng)的值和索引值偎血,可以使用 enumerated()
方法來(lái)進(jìn)行數(shù)組遍歷。enumerated()
返回一個(gè)由索引值和數(shù)據(jù)值組成的元組數(shù)組盯漂。索引值從零開始颇玷,并且每次增加一;如果枚舉一整個(gè)數(shù)組就缆,索引值將會(huì)和數(shù)據(jù)值一一匹配帖渠。你可以把這個(gè)元組分解成臨時(shí)常量或者變量來(lái)進(jìn)行遍歷:
for (index, value) in shoppingList.enumerated() {
print("Item \(String(index + 1)): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas
更多關(guān)于 for-in
循環(huán)的介紹請(qǐng)參見 For 循環(huán)。
集合(Sets)
集合用來(lái)存儲(chǔ)相同類型并且沒(méi)有確定順序的值竭宰。當(dāng)集合元素順序不重要時(shí)或者希望確保每個(gè)元素只出現(xiàn)一次時(shí)可以使用集合而不是數(shù)組空郊。
注意 Swift 的
Set
類型被橋接到 Foundation 中的NSSet
類。關(guān)于使用 Foundation 和 Cocoa 中
Set
的知識(shí)切揭,參見 Bridging Between Set and NSSet
集合類型的哈希值
一個(gè)類型為了存儲(chǔ)在集合中狞甚,該類型必須是可哈希化的——也就是說(shuō)伴箩,該類型必須提供一個(gè)方法來(lái)計(jì)算它的哈希值入愧。一個(gè)哈希值是 Int
類型的,相等的對(duì)象哈希值必須相同嗤谚,比如 a == b
,因此必須 a.hashValue == b.hashValue
棺蛛。
Swift 的所有基本類型(比如 String
、Int
巩步、Double
和 Bool
)默認(rèn)都是可哈吓陨蓿化的,可以作為集合值的類型或者字典鍵的類型椅野。沒(méi)有關(guān)聯(lián)值的枚舉成員值(在 枚舉 有講述)默認(rèn)也是可哈现粘化的。
注意
你可以使用自定義的類型作為集合值的類型或者是字典鍵的類型竟闪,但需要使自定義類型遵循 Swift 標(biāo)準(zhǔn)庫(kù)中的
Hashable
協(xié)議离福。遵循Hashable
協(xié)議的類型需要提供一個(gè)類型為Int
的可讀屬性hashValue
。由類型的hashValue
屬性返回的值不需要在同一程序的不同執(zhí)行周期或者不同程序之間保持相同炼蛤。因?yàn)?
Hashable
協(xié)議遵循Equatable
協(xié)議妖爷,所以遵循該協(xié)議的類型也必須提供一個(gè)“是否相等”運(yùn)算符(==
)的實(shí)現(xiàn)。這個(gè)Equatable
協(xié)議要求任何遵循==
實(shí)現(xiàn)的實(shí)例間都是一種相等的關(guān)系理朋。也就是說(shuō)絮识,對(duì)于a,b,c
三個(gè)值來(lái)說(shuō)绿聘,==
的實(shí)現(xiàn)必須滿足下面三種情況:
a == a
(自反性)
a == b
意味著b == a
(對(duì)稱性)
a == b && b == c
意味著a == c
(傳遞性)關(guān)于遵循協(xié)議的更多信息,請(qǐng)看 協(xié)議次舌。
集合類型語(yǔ)法
Swift 中的集合類型被寫為 Set<Element>
熄攘,這里的 Element
表示集合中允許存儲(chǔ)的類型。和數(shù)組不同的是彼念,集合沒(méi)有等價(jià)的簡(jiǎn)化形式挪圾。
創(chuàng)建和構(gòu)造一個(gè)空的集合
你可以通過(guò)構(gòu)造器語(yǔ)法創(chuàng)建一個(gè)特定類型的空集合:
var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
// 打印“l(fā)etters is of type Set<Character> with 0 items.”
注意
通過(guò)構(gòu)造器,這里
letters
變量的類型被推斷為Set<Character>
逐沙。
此外洛史,如果上下文提供了類型信息,比如作為函數(shù)的參數(shù)或者已知類型的變量或常量酱吝,你可以通過(guò)一個(gè)空的數(shù)組字面量創(chuàng)建一個(gè)空的集合:
letters.insert("a")
// letters 現(xiàn)在含有1個(gè) Character 類型的值
letters = []
// letters 現(xiàn)在是一個(gè)空的 Set也殖,但是它依然是 Set<Character> 類型
用數(shù)組字面量創(chuàng)建集合
你可以使用數(shù)組字面量來(lái)構(gòu)造集合,相當(dāng)于一種簡(jiǎn)化的形式將一個(gè)或者多個(gè)值作為集合元素务热。
下面的例子創(chuàng)建一個(gè)稱之為 favoriteGenres
的集合來(lái)存儲(chǔ) String
類型的值:
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres 被構(gòu)造成含有三個(gè)初始值的集合
這個(gè) favoriteGenres
變量被聲明為“一個(gè) String
值的集合”忆嗜,寫為 Set<String>
。由于這個(gè)特定集合指定了值為 String
類型崎岂,所以它只允許存儲(chǔ) String
類型值捆毫。這里的 favoriteGenres
變量有三個(gè) String
類型的初始值("Rock"
,"Classical"
和 "Hip hop"
)冲甘,以數(shù)組字面量的形式書寫绩卤。
注意
favoriteGenres
被聲明為一個(gè)變量(擁有var
標(biāo)示符)而不是一個(gè)常量(擁有let
標(biāo)示符),因?yàn)樗锩娴脑貙?huì)在之后的例子中被增加或者移除。
一個(gè)集合類型不能從數(shù)組字面量中被直接推斷出來(lái)江醇,因此 Set
類型必須顯式聲明濒憋。然而,由于 Swift 的類型推斷功能陶夜,如果你想使用一個(gè)數(shù)組字面量構(gòu)造一個(gè)集合并且與該數(shù)組字面量中的所有元素類型相同凛驮,那么無(wú)須寫出集合的具體類型。favoriteGenres
的構(gòu)造形式可以采用簡(jiǎn)化的方式代替:
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
由于數(shù)組字面量中的所有元素類型相同条辟,Swift 可以推斷出 Set<String>
作為 favoriteGenres
變量的正確類型黔夭。
訪問(wèn)和修改一個(gè)集合
你可以通過(guò)集合的屬性和方法來(lái)對(duì)其進(jìn)行訪問(wèn)和修改。
為了獲取一個(gè)集合中元素的數(shù)量羽嫡,可以使用其只讀屬性 count
:
print("I have \(favoriteGenres.count) favorite music genres.")
// 打印“I have 3 favorite music genres.”
使用布爾屬性 isEmpty
作為一個(gè)縮寫形式去檢查 count
屬性是否為 0
:
if favoriteGenres.isEmpty {
print("As far as music goes, I'm not picky.")
} else {
print("I have particular music preferences.")
}
// 打印“I have particular music preferences.”
你可以通過(guò)調(diào)用集合的 insert(_:)
方法來(lái)添加一個(gè)新元素:
favoriteGenres.insert("Jazz")
// favoriteGenres 現(xiàn)在包含4個(gè)元素
你可以通過(guò)調(diào)用集合的 remove(_:)
方法去刪除一個(gè)元素本姥,如果它是該集合的一個(gè)元素則刪除它并且返回它的值,若該集合不包含它杭棵,則返回 nil
婚惫。另外,集合可以通過(guò) removeAll()
方法刪除所有元素。
if let removedGenre = favoriteGenres.remove("Rock") {
print("\(removedGenre)? I'm over it.")
} else {
print("I never much cared for that.")
}
// 打印“Rock? I'm over it.”
使用 contains(_:)
方法去檢查集合中是否包含一個(gè)特定的值:
if favoriteGenres.contains("Funk") {
print("I get up on the good foot.")
} else {
print("It's too funky in here.")
}
// 打印“It's too funky in here.”
遍歷一個(gè)集合
你可以在一個(gè) for-in
循環(huán)中遍歷一個(gè)集合中的所有值辰妙。
for genre in favoriteGenres {
print("\(genre)")
}
// Classical
// Jazz
// Hip hop
更多關(guān)于 for-in
循環(huán)的信息,參見 For 循環(huán)甫窟。
Swift 的 Set
類型沒(méi)有確定的順序密浑,為了按照特定順序來(lái)遍歷一個(gè)集合中的值可以使用 sorted()
方法,它將返回一個(gè)有序數(shù)組粗井,這個(gè)數(shù)組的元素排列順序由操作符 <
對(duì)元素進(jìn)行比較的結(jié)果來(lái)確定尔破。
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
// Classical
// Hip hop
// Jazz
集合操作
你可以高效地完成集合的一些基本操作,比如把兩個(gè)集合組合到一起浇衬,判斷兩個(gè)集合共有元素懒构,或者判斷兩個(gè)集合是否全包含,部分包含或者不相交耘擂。
基本集合操作
下面的插圖描述了兩個(gè)集合 a
和 b
胆剧,以及通過(guò)陰影部分的區(qū)域顯示集合各種操作的結(jié)果。
使用
intersection(_:)
方法根據(jù)兩個(gè)集合的交集創(chuàng)建一個(gè)新的集合醉冤。使用
symmetricDifference(_:)
方法根據(jù)兩個(gè)集合不相交的值創(chuàng)建一個(gè)新的集合秩霍。使用
union(_:)
方法根據(jù)兩個(gè)集合的所有值創(chuàng)建一個(gè)新的集合。使用
subtracting(_:)
方法根據(jù)不在另一個(gè)集合中的值創(chuàng)建一個(gè)新的集合蚁阳。
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]
集合成員關(guān)系和相等
下面的插圖描述了三個(gè)集合 a
铃绒、b
和 c
,以及通過(guò)重疊區(qū)域表述集合間共享的元素螺捐。集合 a
是集合 b
的父集合颠悬,因?yàn)?a
包含了 b
中所有的元素。相反的定血,集合 b
是集合 a
的子集合赔癌,因?yàn)閷儆?b
的元素也被 a
包含。集合 b
和集合 c
是不相交的澜沟,因?yàn)樗鼈冎g沒(méi)有共同的元素届榄。
使用“是否相等”運(yùn)算符(
==
)來(lái)判斷兩個(gè)集合包含的值是否全部相同。使用
isSubset(of:)
方法來(lái)判斷一個(gè)集合中的所有值是否也被包含在另外一個(gè)集合中倔喂。使用
isSuperset(of:)
方法來(lái)判斷一個(gè)集合是否包含另一個(gè)集合中所有的值铝条。使用
isStrictSubset(of:)
或者isStrictSuperset(of:)
方法來(lái)判斷一個(gè)集合是否是另外一個(gè)集合的子集合或者父集合并且兩個(gè)集合并不相等。使用
isDisjoint(with:)
方法來(lái)判斷兩個(gè)集合是否不含有相同的值(是否沒(méi)有交集)席噩。
let houseAnimals: Set = ["??", "??"]
let farmAnimals: Set = ["??", "??", "??", "??", "??"]
let cityAnimals: Set = ["??", "??"]
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true
字典
字典是一種無(wú)序的集合班缰,它存儲(chǔ)的是鍵值對(duì)之間的關(guān)系,其所有鍵的值需要是相同的類型悼枢,所有值的類型也需要相同埠忘。每個(gè)值(value)都關(guān)聯(lián)唯一的鍵(key),鍵作為字典中這個(gè)值數(shù)據(jù)的標(biāo)識(shí)符。和數(shù)組中的數(shù)據(jù)項(xiàng)不同莹妒,字典中的數(shù)據(jù)項(xiàng)并沒(méi)有具體順序名船。你在需要通過(guò)標(biāo)識(shí)符(鍵)訪問(wèn)數(shù)據(jù)的時(shí)候使用字典,這種方法很大程度上和在現(xiàn)實(shí)世界中使用字典查字義的方法一樣旨怠。
注意
Swift 的
Dictionary
類型被橋接到 Foundation 的NSDictionary
類渠驼。更多關(guān)于在 Foundation 和 Cocoa 中使用
Dictionary
類型的信息,參見 Bridging Between Dictionary and NSDictionary鉴腻。
字典類型簡(jiǎn)化語(yǔ)法
Swift 的字典使用 Dictionary<Key, Value>
定義迷扇,其中 Key
是一種可以在字典中被用作鍵的類型,Value
是字典中對(duì)應(yīng)于這些鍵所存儲(chǔ)值的數(shù)據(jù)類型爽哎。
注意
一個(gè)字典的
Key
類型必須遵循Hashable
協(xié)議蜓席,就像Set
的值類型。
你也可以用 [Key: Value]
這樣簡(jiǎn)化的形式去表示字典類型课锌。雖然這兩種形式功能上相同厨内,但是后者是首選,并且本教程中涉及到字典類型時(shí)通篇采用后者渺贤。
創(chuàng)建一個(gè)空字典
你可以像數(shù)組一樣使用構(gòu)造語(yǔ)法創(chuàng)建一個(gè)擁有確定類型的空字典:
var namesOfIntegers: [Int: String] = [:]
// namesOfIntegers 是一個(gè)空的 [Int: String] 字典
這個(gè)例子創(chuàng)建了一個(gè) [Int: String]
類型的空字典來(lái)儲(chǔ)存整數(shù)的英語(yǔ)命名隘庄。它的鍵是 Int
型,值是 String
型癣亚。
如果上下文已經(jīng)提供了類型信息丑掺,你可以使用空字典字面量來(lái)創(chuàng)建一個(gè)空字典,記作 [:]
(一對(duì)方括號(hào)中放一個(gè)冒號(hào)):
namesOfIntegers[16] = "sixteen"
// namesOfIntegers 現(xiàn)在包含一個(gè)鍵值對(duì)
namesOfIntegers = [:]
// namesOfIntegers 又成為了一個(gè) [Int: String] 類型的空字典
用字典字面量創(chuàng)建字典
你可以使用字典字面量來(lái)構(gòu)造字典述雾,這和剛才介紹過(guò)的數(shù)組字面量擁有相似語(yǔ)法街州。字典字面量是一種將一個(gè)或多個(gè)鍵值對(duì)寫作 Dictionary
集合的快捷途徑。
一個(gè)鍵值對(duì)是一個(gè)鍵和一個(gè)值的結(jié)合體玻孟。在字典字面量中唆缴,每一個(gè)鍵值對(duì)的鍵和值都由冒號(hào)分割。這些鍵值對(duì)構(gòu)成一個(gè)列表黍翎,其中這些鍵值對(duì)由逗號(hào)分割面徽、并整體被包裹在一對(duì)方括號(hào)中:
[key 1: value 1, key 2: value 2, key 3: value 3]
下面的例子創(chuàng)建了一個(gè)存儲(chǔ)國(guó)際機(jī)場(chǎng)名稱的字典。在這個(gè)字典中鍵是三個(gè)字母的國(guó)際航空運(yùn)輸相關(guān)代碼匣掸,值是機(jī)場(chǎng)名稱:
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
airports
字典被聲明為一種 [String: String]
類型趟紊,這意味著這個(gè)字典的鍵和值都是 String
類型。
注意
airports
字典被聲明為變量(用var
關(guān)鍵字)而不是常量(用let
關(guān)鍵字)因?yàn)楹竺鏁?huì)有更多的機(jī)場(chǎng)信息被添加到這個(gè)字典中碰酝。
airports
字典使用字典字面量初始化霎匈,包含兩個(gè)鍵值對(duì)。第一對(duì)的鍵是 YYZ
送爸,值是 Toronto Pearson
铛嘱。第二對(duì)的鍵是 DUB
暖释,值是 Dublin
。
這個(gè)字典語(yǔ)句包含了兩個(gè) String: String
類型的鍵值對(duì)墨吓。它們對(duì)應(yīng) airports
變量聲明的類型(一個(gè)只有 String
鍵和 String
值的字典)球匕,所以這個(gè)字典字面量的賦值是一種方式用來(lái)構(gòu)造擁有兩個(gè)初始數(shù)據(jù)項(xiàng)的 airport
字典。
和數(shù)組一樣帖烘,你在用字典字面量構(gòu)造字典時(shí)亮曹,如果它的鍵和值都有各自一致的類型,那么就不必寫出字典的類型蚓让。 airports
字典也可以用這種簡(jiǎn)短方式定義:
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
因?yàn)檫@個(gè)語(yǔ)句中所有的鍵和值都各自擁有相同的數(shù)據(jù)類型,Swift 可以推斷出 [String: String]
是 airports
字典的正確類型讥珍。
訪問(wèn)和修改字典
你可以通過(guò)字典的方法和屬性來(lái)訪問(wèn)和修改字典历极,或者通過(guò)使用下標(biāo)語(yǔ)法。
和數(shù)組一樣衷佃,可以通過(guò) Dictionary
的只讀屬性 count
來(lái)獲取字典的數(shù)據(jù)項(xiàng)數(shù)量:
print("The dictionary of airports contains \(airports.count) items.")
// 打印“The dictionary of airports contains 2 items.”(這個(gè)字典有兩個(gè)數(shù)據(jù)項(xiàng))
使用布爾屬性 isEmpty
作為一個(gè)縮寫形式去檢查 count
屬性是否為 0
:
if airports.isEmpty {
print("The airports dictionary is empty.")
} else {
print("The airports dictionary is not empty.")
}
// 打印“The airports dictionary is not empty.”
你可以通過(guò)下標(biāo)語(yǔ)法來(lái)給字典添加新的數(shù)據(jù)項(xiàng)趟卸。可以使用一個(gè)恰當(dāng)類型的鍵作為下標(biāo)索引氏义,并且分配恰當(dāng)類型的新值:
airports["LHR"] = "London"
// airports 字典現(xiàn)在有三個(gè)數(shù)據(jù)項(xiàng)
也可以使用下標(biāo)語(yǔ)法來(lái)改變特定鍵對(duì)應(yīng)的值:
airports["LHR"] = "London Heathrow"
// “LHR”對(duì)應(yīng)的值被改為“London Heathrow”
作為一種替代下標(biāo)語(yǔ)法的方式锄列,字典的 updateValue(_:forKey:)
方法可以設(shè)置或者更新特定鍵對(duì)應(yīng)的值。就像上面所示的下標(biāo)示例惯悠,updateValue(_:forKey:)
方法在這個(gè)鍵不存在對(duì)應(yīng)值的時(shí)候會(huì)設(shè)置新值或者在存在時(shí)更新已存在的值邻邮。和下標(biāo)的方式不同,updateValue(_:forKey:)
這個(gè)方法返回更新值之前的原值克婶。這樣使得你可以檢查更新是否成功筒严。
updateValue(_:forKey:)
方法會(huì)返回對(duì)應(yīng)值類型的可選類型。舉例來(lái)說(shuō):對(duì)于存儲(chǔ) String
值的字典情萤,這個(gè)函數(shù)會(huì)返回一個(gè) String?
或者“可選 String
”類型的值鸭蛙。如果有值存在于更新前,則這個(gè)可選值包含了舊值筋岛,否則它將會(huì)是 nil
:
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
print("The old value for DUB was \(oldValue).")
}
// 輸出“The old value for DUB was Dublin.”
你也可以使用下標(biāo)語(yǔ)法來(lái)在字典中檢索特定鍵對(duì)應(yīng)的值娶视。因?yàn)橛锌赡苷?qǐng)求的鍵沒(méi)有對(duì)應(yīng)的值存在,字典的下標(biāo)訪問(wèn)會(huì)返回對(duì)應(yīng)值類型的可選類型睁宰。如果這個(gè)字典包含請(qǐng)求鍵所對(duì)應(yīng)的值肪获,下標(biāo)會(huì)返回一個(gè)包含這個(gè)存在值的可選類型,否則將返回 nil
:
if let airportName = airports["DUB"] {
print("The name of the airport is \(airportName).")
} else {
print("That airport is not in the airports dictionary.")
}
// 打印“The name of the airport is Dublin Airport.”
還可以使用下標(biāo)語(yǔ)法通過(guò)將某個(gè)鍵的對(duì)應(yīng)值賦值為 nil
來(lái)從字典里移除一個(gè)鍵值對(duì):
airports["APL"] = "Apple Internation"
// “Apple Internation”不是真的 APL 機(jī)場(chǎng)柒傻,刪除它
airports["APL"] = nil
// APL 現(xiàn)在被移除了
此外贪磺,removeValue(forKey:)
方法也可以用來(lái)在字典中移除鍵值對(duì)。這個(gè)方法在鍵值對(duì)存在的情況下會(huì)移除該鍵值對(duì)并且返回被移除的值或者在沒(méi)有對(duì)應(yīng)值的情況下返回 nil
:
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.")
}
// 打印“The removed airport's name is Dublin Airport.”
字典遍歷
你可以使用 for-in
循環(huán)來(lái)遍歷某個(gè)字典中的鍵值對(duì)诅愚。每一個(gè)字典中的數(shù)據(jù)項(xiàng)都以 (key, value)
元組形式返回寒锚,并且可以使用臨時(shí)常量或者變量來(lái)分解這些元組:
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
// YYZ: Toronto Pearson
// LHR: London Heathrow
更多關(guān)于 for-in
循環(huán)的信息劫映,參見 For 循環(huán)。
通過(guò)訪問(wèn) keys
或者 values
屬性刹前,你也可以遍歷字典的鍵或者值:
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
如果你需要使用某個(gè)字典的鍵集合或者值集合來(lái)作為某個(gè)接受 Array
實(shí)例的 API 的參數(shù)泳赋,可以直接使用 keys
或者 values
屬性構(gòu)造一個(gè)新數(shù)組:
let airportCodes = [String](airports.keys)
// airportCodes 是 ["YYZ", "LHR"]
let airportNames = [String](airports.values)
// airportNames 是 ["Toronto Pearson", "London Heathrow"]
Swift 的 Dictionary
是無(wú)序集合類型。為了以特定的順序遍歷字典的鍵或值喇喉,可以對(duì)字典的 keys
或 values
屬性使用 sorted()
方法祖今。
繼續(xù)閱讀 Swift - 控制流