Swift提供了三種主要的集合類型,array數(shù)組, set集合, dictionary字典,用于存儲值集合。
數(shù)組array是值的有序集合。
集合set是惟一值的無序集合。
字典dictionary是鍵值關(guān)聯(lián)的無序集合。
Swift中的數(shù)組、集合和字典總是清楚地知道它們可以存儲的值和鍵的類型。這意味著不能錯誤地將錯誤類型的值插入集合。這還意味著您可以確定從集合中檢索的值的類型。
Mutability of Collections 可變性
如果創(chuàng)建數(shù)組、集合或字典,并將其分配給變量,則所創(chuàng)建的集合將是可變的。這意味著,通過添加、刪除或更改集合中的項(xiàng),可以在創(chuàng)建集合之后更改(或修改)集合。如果將數(shù)組、集合或字典賦給常量,則該集合是不可變的,且其大小和內(nèi)容不能更改。
注意:在集合不需要更改的所有情況下,創(chuàng)建不可變集合是一個很好的實(shí)踐。這樣做使您更容易推斷代碼,并使Swift編譯器能夠優(yōu)化您創(chuàng)建的集合的性能。
Arrays 數(shù)組
數(shù)組在有序列表中存儲相同類型的值。相同的值可以在數(shù)組的不同位置多次出現(xiàn)。
Array Type Shorthand Syntax 數(shù)組類型簡寫語法
Swift數(shù)組的類型被完整地寫成array ,其中Element是數(shù)組允許存儲的值的類型。您還可以將數(shù)組的類型以簡寫形式寫成[Element]。雖然這兩種形式在功能上是相同的,但是在整個教程指南中,當(dāng)引用數(shù)組的類型時,首選使用簡寫形式。
Creating an Empty Array 創(chuàng)建一個空數(shù)組
可以使用初始化器語法創(chuàng)建特定類型的空數(shù)組:
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// Prints "someInts is of type [Int] with 0 items."
注意someInts變量的類型從初始化器的類型推斷為[Int]。
或者,如果上下文已經(jīng)提供了類型信息,例如函數(shù)參數(shù)或已經(jīng)類型化的變量或常量,您可以使用一個空數(shù)組文字創(chuàng)建一個空數(shù)組,它被寫成:
someInts.append(3)
// someInts now contains 1 value of type Int
someInts = []
// someInts is now an empty array, but is still of type [Int]
Creating an Array with a Default Value 創(chuàng)建具有默認(rèn)值的數(shù)組
Swift的數(shù)組類型還提供了一個初始化器,用于創(chuàng)建一個特定大小的數(shù)組,其所有值都設(shè)置為相同的默認(rèn)值。傳遞給初始化器一個適當(dāng)類型的默認(rèn)值(稱為repeat):該值在新數(shù)組中重復(fù)的次數(shù)(稱為count):
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
Creating an Array by Adding Two Arrays Together 通過兩個數(shù)組加起來創(chuàng)建新數(shù)組
通過使用加法運(yùn)算符(+)將兩個具有兼容類型的現(xiàn)有數(shù)組相加,可以創(chuàng)建一個新數(shù)組。新數(shù)組的類型是從兩個相加數(shù)組的類型推斷出來的:
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]
Creating an Array with an Array Literal 使用數(shù)組字面量創(chuàng)建數(shù)組
您還可以使用數(shù)組文字初始化數(shù)組,這是將一個或多個值編寫為數(shù)組集合的一種簡寫方法。數(shù)組文字被寫成一列值,用逗號分隔,用一對方括號括起來:
[value1, value2, value3]
下面的例子創(chuàng)建了一個名為shoppingList的數(shù)組來存儲字符串值:
var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList has been initialized with two initial items
shoppingList變量被聲明為“字符串值的數(shù)組”,被寫成[string]。因?yàn)檫@個特定的數(shù)組指定了字符串的值類型,所以它只允許存儲字符串值。在這里,shoppingList數(shù)組用兩個字符串值(“Eggs”和“Milk”)初始化,并在數(shù)組文本中編寫。
shoppingList數(shù)組被聲明為一個變量(使用var導(dǎo)入器),而不是一個常量(使用let導(dǎo)入器),因?yàn)樵谙旅娴氖纠校嗟纳唐繁惶砑拥劫徫锪斜碇小?/p>
在本例中,數(shù)組文字只包含兩個字符串值。這與shoppingList變量的聲明類型相匹配(一個數(shù)組只能包含字符串值),因此數(shù)組文字的賦值被允許作為用兩個初始項(xiàng)初始化shoppingList的方法。
由于Swift的類型推斷,如果使用包含相同類型值的數(shù)組文字初始化數(shù)組,則不必編寫數(shù)組的類型。shoppingList的初始化可以寫成更短的形式:
var shoppingList = ["Eggs", "Milk"]
因?yàn)閿?shù)組文字中的所有值都是同一類型的,Swift可以推斷[String]是shoppingList變量的正確類型。
Accessing and Modifying an Array 訪問和修改數(shù)組
您可以通過數(shù)組的方法和屬性或使用下標(biāo)語法訪問和修改數(shù)組。
若要查明數(shù)組中的項(xiàng)數(shù),請檢查其只讀計數(shù)屬性:
print("The shopping list contains \(shoppingList.count) items.")
// Prints "The shopping list contains 2 items."
使用Boolean isEmpty屬性作為檢查count屬性是否等于0的快捷方式:
if shoppingList.isEmpty {
print("The shopping list is empty.")
} else {
print("The shopping list is not empty.")
}
// Prints "The shopping list is not empty."
您可以通過調(diào)用數(shù)組的append(_:)方法將新項(xiàng)添加到數(shù)組的末尾:
shoppingList.append("Flour")
// shoppingList now contains 3 items, and someone is making pancakes
也可以使用 += 運(yùn)算符:
shoppingList += ["Baking Powder"]
// shoppingList now contains 4 items
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList now contains 7 items
使用下標(biāo)語法從數(shù)組中檢索一個值,在數(shù)組名稱之后立即在方括號中傳遞要檢索的值的索引:
var firstItem = shoppingList[0]
// firstItem is equal to "Eggs"
注意:數(shù)組中的第一項(xiàng)索引為0,而不是1。Swift中的數(shù)組總是零索引的。
可以使用下標(biāo)語法在給定索引處更改現(xiàn)有值:
shoppingList[0] = "Six eggs"
// the first item in the list is now equal to "Six eggs" rather than "Eggs"
使用下標(biāo)語法時,指定的索引必須有效。例如,編寫shoppingList[shoppingList.count] = "Salt"嘗試將一個項(xiàng)追加到數(shù)組末尾會導(dǎo)致運(yùn)行時錯誤。
您還可以使用下標(biāo)語法立即更改一個值范圍,即使替換值集的長度與要替換的范圍不同。下面的例子用“香蕉”和“蘋果”代替“巧克力醬”、“奶酪”和“黃油”:
shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList now contains 6 items
這里是將4-6三個元素替換成2個元素了
若要在指定索引處將項(xiàng)插入數(shù)組,請調(diào)用數(shù)組的insert(_:at:)方法:
shoppingList.insert("Maple Syrup", at: 0)
// shoppingList now contains 7 items
// "Maple Syrup" is now the first item in the list
類似地,使用remove(at:)方法從數(shù)組中刪除項(xiàng)。此方法刪除指定索引處的項(xiàng)并返回已刪除的項(xiàng)(如果不需要,可以忽略返回值):
let mapleSyrup = shoppingList.remove(at: 0)
注意:如果試圖訪問或修改超出數(shù)組現(xiàn)有邊界的索引值,則會觸發(fā)運(yùn)行時錯誤。通過將索引與數(shù)組的count屬性進(jìn)行比較,可以在使用索引之前檢查索引是否有效。數(shù)組中最大的有效索引是count - 1,因?yàn)閿?shù)組是從0開始索引的。
如果希望從數(shù)組中刪除最后一項(xiàng),請使用removeLast()方法而不是remove(at:)方法,以避免查詢數(shù)組的count屬性。與remove(at:)方法類似,removeLast()返回已刪除的項(xiàng):
let apples = shoppingList.removeLast()
Iterating Over an Array 遍歷數(shù)組
你可以用for-in循環(huán)遍歷數(shù)組中的所有值:
for item in shoppingList {
print(item)
}
如果需要每個項(xiàng)的整數(shù)索引及其值,則使用枚舉()方法迭代數(shù)組。對于數(shù)組中的每個項(xiàng),枚舉()方法返回一個由整數(shù)和項(xiàng)組成的元組。整數(shù)從0開始,每一項(xiàng)加1;如果枚舉整個數(shù)組,這些整數(shù)匹配項(xiàng)的索引。您可以將元組分解為臨時常量或變量作為迭代的一部分:
for (index, value) in shoppingList.enumerated() {
print("Item \(index + 1): \(value)")
}
Sets 集合
集合在沒有定義順序的集合中存儲同一類型的不同值。
當(dāng)項(xiàng)的順序不重要時,或者需要確保項(xiàng)只出現(xiàn)一次時,可以使用集合而不是數(shù)組。
Hash Values for Set Types set類型的哈希值
一種類型必須是可hashable的,以便存儲在一個集合中——也就是說,類型必須提供一種為自己計算哈希值的方法。哈希值是一個Int值,它對于所有比較相同的對象都是相同的,因此,如果a == b,那么它就遵循a.hashValue = = b.hashValue。
Swift的所有基本類型(如String、Int、Double和Bool)在默認(rèn)情況下都是可hashable的,可以用作set value類型或dictionary key類型。沒有關(guān)聯(lián)值的枚舉用例值(如枚舉中所述)在默認(rèn)情況下也是可hashable的。
您可以使用自己的自定義類型作為set value類型或dictionary key類型,方法是使它們符合Swift標(biāo)準(zhǔn)庫中的Hashable協(xié)議。符合Hashable協(xié)議的類型必須提供一個名為hashValue的可獲取Int屬性。類型的hashValue屬性返回的值在同一程序的不同執(zhí)行或不同程序中不需要相同。
因?yàn)镠ashable協(xié)議符合Equatable,符合Equatable的類型還必須提供equals操作符(==)的實(shí)現(xiàn)。Equatable協(xié)議要求任何符合==的實(shí)現(xiàn)都是等價關(guān)系。也就是說,對于所有值a、b和c, ==的實(shí)現(xiàn)必須滿足以下三個條件:
- a == a (Reflexivity)
- a == b implies b == a (Symmetry)
- a == b && b == c implies a == c (Transitivity)
Set Type Syntax set類型語法
Swift集合的類型被寫成set ,其中Element是允許該集合存儲的類型。與數(shù)組不同,集合沒有等價的簡寫形式。
Creating and Initializing an Empty Set 創(chuàng)建和初始化空集合set
創(chuàng)建一個元素類型的為Character 的空集合:
var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
// Prints "letters is of type Set<Character> with 0 items."
或者,如果上下文已經(jīng)提供了類型信息,例如函數(shù)參數(shù)或已經(jīng)類型化的變量或常量,則可以使用空數(shù)組文字創(chuàng)建一個空集:
letters.insert("a")
// letters now contains 1 value of type Character
letters = []
// letters is now an empty set, but is still of type Set<Character>
Creating a Set with an Array Literal 使用數(shù)組創(chuàng)建集合set
您還可以使用數(shù)組文字初始化一個集合,作為將一個或多個值寫入集合的簡寫方法。
下面的例子創(chuàng)建了一個名為favoritegenre的集合來存儲字符串值:
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres has been initialized with three initial items
指定了set集合中存儲類型為String
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
Swift 可以類型推斷
Accessing and Modifying a Set 訪問和修改set
您可以通過它的方法和屬性訪問和修改一個集合。
元素個數(shù)
print("I have \(favoriteGenres.count) favorite music genres.")
// Prints "I have 3 favorite music genres."
是否為空
if favoriteGenres.isEmpty {
print("As far as music goes, I'm not picky.")
} else {
print("I have particular music preferences.")
}
插入一個新元素
favoriteGenres.insert("Jazz")
移除元素
移除單個元素 如果集合中有改元素,返回該元素,沒有返回nil
if let removedGenre = favoriteGenres.remove("Rock") {
print("\(removedGenre)? I'm over it.")
} else {
print("I never much cared for that.")
}
// Prints "Rock? I'm over it."
移除所有元素
favoriteGenres.removeAll()
是否包含某個元素
if favoriteGenres.contains("Funk") {
print("I get up on the good foot.")
} else {
print("It's too funky in here.")
}
遍歷set集合
可以使用for-in遍歷set集合
for genre in favoriteGenres {
print("\(genre)")
}
Swift的Set類型沒有定義順序。要按特定順序遍歷集合的值,可以使用ordered()方法,該方法將集合的元素作為使用<操作符排序的數(shù)組返回。
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
Performing Set Operations 執(zhí)行set操作
您可以有效地執(zhí)行基本的集合操作,例如將兩個集合組合在一起,確定兩個集合有哪些值相同,或者確定兩個集合是否包含所有、一些或沒有相同的值。
Fundamental Set Operations 基本設(shè)置操作
下圖描述了兩個集合—a和b—以及用陰影區(qū)域表示的各種集合操作的結(jié)果。
- 使用 intersection(_:) 方法獲取兩個集合相同的部分
- 使用symmetricDifference(_:) 方法獲取兩個集合不相同的部分
- 使用 union(_:) 方法獲取兩個集合的所有元素
- 使用 subtracting(_:) 方法獲取與當(dāng)前集合減去相同元素的部分
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]
Set Membership and Equality set成員關(guān)系和相等
下圖描述了三個集合a、b和c,其中重疊的區(qū)域表示集合之間共享的元素。設(shè)置一個是集的超集b,因?yàn)榘怂性豣。相反地,b是集的一個子集,因?yàn)樗性豣也包含一組。b, c是不相交的,因?yàn)樗麄儧]有共同之處。
- 使用 == 確定兩個set集合中元素是否完全相同。
是返回true,否則返回false - 使用 isSubset(of:) 方法確定當(dāng)前集合是否是另一個集合的子集(當(dāng)前集合的所有元素在另一個集合中都可以找到)。
是返回true,否則返回false - 使用 isSuperset(of:) 方法 確定當(dāng)前集合是否是另一個集合的超集(當(dāng)前集合中可以找到另一個集合的所有元素)。
是返回true,否則返回false - 使用 isStrictSubset(of:) 方法來確定當(dāng)前集合是否是另一個集合的真子集(是子集且不完全相等)。
是返回true,否則返回false - 使用 isStrictSuperset(of:) 方法來確定當(dāng)前集合是否是另一個集合的真超集(是超集且不完全相等)。
是返回true,否則返回false - 使用 isDisjoint(with:) 方法來確定兩個集合是否沒有共同的元素。
有相同元素返回false,沒有返回true
let houseAnimals: Set = ["??", "??"]
let farmAnimals: Set = ["??", "??", "??", "??", "??"]
let cityAnimals: Set = ["??", "??"]
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true
Dictionary 字典
字典在沒有定義順序的集合中存儲相同類型的鍵和相同類型的值之間的關(guān)聯(lián)。
每個value都與一個惟一的key相關(guān)聯(lián),該key在字典中充當(dāng)該value的標(biāo)識符。
與數(shù)組中的item不同,字典中的item沒有指定的順序。
當(dāng)您需要根據(jù)值的標(biāo)識符查找值時,您將使用字典,這與實(shí)際字典用于查找特定單詞的定義非常相似。
Dictionary Type Shorthand Syntax 字典簡寫語法
Swift字典的類型完整地寫成Dictionary<Key,Value> ,其中Key是字典中每項(xiàng)標(biāo)識符值的類型,Value是字典為這些鍵存儲的值的類型。
注意:字典的鍵類型必須符合Hashable協(xié)議,就像集合的值類型一樣。
您還可以將字典的類型以簡寫形式寫成[Key: Value]。雖然這兩種形式在功能上是相同的,但是在本指南中,在引用字典的類型時,首選使用速記形式。
Creating an Empty Dictionary 創(chuàng)建一個空字典
var namesOfIntegers = [Int: String]()
// namesOfIntegers is an empty [Int: String] dictionary
這個例子創(chuàng)建了一個類型為[Int: String]的空字典來存儲人類可讀的整數(shù)值名稱。它的鍵類型為Int,值類型為String。
如果上下文已經(jīng)提供了類型信息,您可以使用一個空字典文本創(chuàng)建一個空字典,它被寫成 [:]
namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]
使用字典字面量創(chuàng)建字典
您還可以使用字典字面量初始化字典,它的語法與前面看到的數(shù)組字面量類似。dictionary literal是將一個或多個鍵值對編寫為dictionary集合的一種簡寫方法。
鍵值對是鍵和值的組合。在字典文本中,每個鍵值對中的鍵和值之間用冒號分隔。鍵值對以列表形式編寫,用逗號分隔,用一對方括號括起來:
[key1: value1, key2: value2, key3: value3]
下面的示例創(chuàng)建一個字典來存儲國際機(jī)場的名稱。在本詞典中,鍵為三個字母的國際航空運(yùn)輸協(xié)會代碼,值為機(jī)場名稱:
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
機(jī)場字典聲明為具有[String: String]類型,這意味著“其鍵為String類型的字典,其值也為String類型的字典”。
機(jī)場字典被聲明為一個變量(使用var關(guān)鍵字),而不是一個常量(使用let關(guān)鍵字),因?yàn)樵谙旅娴氖纠校嗟臋C(jī)場被添加到字典中。
機(jī)場字典是用包含兩個鍵值對的字典文本初始化的。第一對的鍵是“YYZ”,值是“Toronto Pearson”。第二對鍵值為“DUB”,值為“Dublin”。
這個字典文本包含兩個字符串:字符串對。此鍵-值類型與機(jī)場變量聲明的類型相匹配(只有字符串鍵和字符串值的字典),因此允許分配字典字面量,以便使用兩個初始項(xiàng)初始化機(jī)場字典。
與數(shù)組一樣,如果要用一個字典字面量初始化字典,而字典字面量的鍵和值具有一致的類型,則不必編寫字典的類型。機(jī)場的初始化可以寫成更短的形式:
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
因?yàn)槲淖种械乃墟I都是彼此相同的類型,同樣,所有值都是彼此相同的類型,所以Swift可以推斷[String: String]是機(jī)場字典使用的正確類型。
Accessing and Modifying a Dictionary 訪問和修改字典
您可以通過字典的方法和屬性,或者使用下標(biāo)語法來訪問和修改字典。
與數(shù)組一樣,您可以通過檢查字典的只讀count屬性來查找字典中的項(xiàng)數(shù):
print(airports.count)
輸出2
判斷是否為空字典
if airports.isEmpty {
print("The airports dictionary is empty.")
} else {
print("The airports dictionary is not empty.")
}
可以使用下標(biāo)語法將新項(xiàng)添加到字典中。使用適當(dāng)類型的新鍵作為下標(biāo)索引,并分配適當(dāng)類型的新值:
airports["LHR"] = "London"
您還可以使用下標(biāo)語法來更改與特定鍵關(guān)聯(lián)的值:
airports["LHR"] = "London Heathrow"
作為下標(biāo)的替代方法,使用字典的updateValue(:forKey:)方法來設(shè)置或更新特定鍵的值。與上面的下標(biāo)示例一樣,updateValue(:forKey:)方法在一個鍵不存在的情況下為該鍵設(shè)置一個值,或者在該鍵已經(jīng)存在的情況下更新該值。但是,與下標(biāo)不同,updateValue(_:forKey:)方法在執(zhí)行更新后返回舊值。這使您能夠檢查是否發(fā)生了更新。
updateValue(_:forKey:) 方法的作用是:返回值為可選類型,因?yàn)閗ey可能存在,可能不存在,存在返回key所對應(yīng)的舊值,不存在就返回nil
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
print("The old value for DUB was \(oldValue).")
}
// Prints "The old value for DUB was Dublin."
還可以使用下標(biāo)語法從字典中檢索特定鍵的值。因?yàn)榭梢哉埱笠粋€沒有值的鍵,所以dictionary的下標(biāo)返回dictionary值類型的可選值。如果字典包含請求鍵的值,下標(biāo)返回一個可選值,該值包含該鍵的現(xiàn)有值。否則,下標(biāo)返回nil:
if let airportName = airports["DUB"] {
print("The name of the airport is \(airportName).")
} else {
print("That airport is not in the airports dictionary.")
}
// Prints "The name of the airport is Dublin Airport."
您可以使用下標(biāo)語法,通過為字典中該鍵值對賦值為nil 來刪除該鍵值對:
airports["APL"] = "Apple International"
// "Apple International" is not the real airport for APL, so delete it
airports["APL"] = nil
// APL has now been removed from the dictionary
或者,使用removeValue(forKey:)方法從字典中刪除鍵值對。該方法刪除鍵值對(如果存在)并返回刪除的值,或者返回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.")
}
// Prints "The removed airport's name is Dublin Airport."
Iterating Over a Dictionary 遍歷字典
使用 for-in 遍歷字典
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
您還可以通過訪問字典的鍵和值屬性來檢索字典的鍵或值的可迭代集合:
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
如果你需要使用字典的鍵或值與一個API的數(shù)組實(shí)例,初始化一個新的數(shù)組與鍵或值的屬性:
let airportCodes = [String](airports.keys)
// airportCodes is ["YYZ", "LHR"]
let airportNames = [String](airports.values)
// airportNames is ["Toronto Pearson", "London Heathrow"]
Swift的字典類型沒有定義順序。若要按特定順序遍歷字典的鍵或值,請對其鍵或值屬性使用ordered()方法。