繼續學習Swift文檔,從上一章節:字符串和字符,咱們學習了Swift的字符串和字符相關的內容。集合這個數據結構在咱們項目開發過程當中,也會頻繁被用到,因此須要熟練掌握它的用法。如今,咱們開始學習Swift的集合相關的內容。因爲篇幅較長,這裏分篇來記錄,接下來,開始吧!html
若是你已經熟悉並掌握了集合的相關內容,那麼請閱讀下一章節:控制流git
Swift提供了三種主要的集合類型,即數組、集合和字典,用於存儲值的集合。數組是值的有序集合。集合是唯一值的無序集合。字典是鍵-值關聯的無序集合。 swift
Swift中的數組、集合和字典老是清楚地知道它們能夠存儲的值和鍵的類型。這意味着不能將錯誤類型的值插入到集合中。這還意味着能夠明確知道從集合中檢索的值的類型。注意
Swift的數組、set和dictionary類型被實現爲泛型集合。有關泛型類型和集合的更多信息,請參見泛型。數組
若是您建立了一個數組、一個集合或一個字典,並將其分配給一個變量,那麼所建立的集合將是可變的。這意味着您能夠在集合建立後經過添加、刪除或更改集合中的項來更改(或改變)集合。若是將數組、集合或字典分配給常量,則該集合是不可變的,其大小和內容不能更改。bash
注意
在全部集合不須要更改的狀況下,建立不可變集合是一個很好的實踐。這樣作可使您更容易地推理您的代碼,並使Swift編譯器可以優化您建立的集合的性能。數據結構
數組將相同類型的值存儲在有序列表中。相同的值能夠在數組的不一樣位置出現屢次。app
注意
Swift的數組類型被橋接到Foundation的NSArray類。ide
有關在Foundation和Cocoa中使用數組的更多信息,請參見Array和NSArray之間的橋接。函數
Swift數組的類型被寫成array
你可使用初始化語法建立一個特定類型的空數組:
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// Prints "someInts is of type [Int] with 0 items."
複製代碼
或者,若是上下文已經提供了類型信息,好比一個函數參數或一個已經類型化的變量或常量,你能夠用一個空數組文字建立一個空數組,它寫爲:
someInts.append(3)
// someInts now contains 1 value of type Int
someInts = []
// someInts is now an empty array, but is still of type [Int]
複製代碼
Swift的數組類型還提供了一個初始化器,用於建立一個特定大小的數組,數組的全部值都設置爲相同的默認值。你給初始化器傳遞一個適當類型的默認值(稱爲repeat):和該值在新數組中重複的次數(稱爲count):
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
複製代碼
經過使用加法運算符(+)將兩個具備兼容類型的現有數組相加,能夠建立新的數組。新數組的類型是從你加在一塊兒的兩個數組的類型推斷出來的:
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]
複製代碼
還能夠用數組文字初始化數組,這是將一個或多個值寫入數組集合的一種速記方法。一個數組文字被寫爲一個值的列表,用逗號分隔,由一對方括號包圍:
[value 1, value 2, value 3]
複製代碼
下面的例子建立了一個名爲shoppingList的數組來存儲字符串值:
var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList has been initialized with two initial items
複製代碼
shoppingList變量被聲明爲「字符串值數組」,寫爲[string]。由於這個特定數組指定了字符串的值類型,因此只容許存儲字符串值。在這裏,shoppingList數組用兩個字符串值(「Eggs」和「Milk」)初始化,用數組文字編寫。
注意
shoppingList數組被聲明爲一個變量(使用var導入器),而不是一個常量(使用let導入器),由於在下面的示例中有更多的條目被添加到購物列表中。
在本例中,數組文字只包含兩個字符串值。這與shoppingList變量聲明的類型(只能包含字符串值的數組)相匹配,所以容許數組文字的賦值做爲用兩個初始項初始化shoppingList的一種方式。
因爲Swift的類型推斷,若是您使用包含相同類型值的數組文本初始化數組,則沒必要編寫數組的類型。shoppingList的初始化能夠寫成更短的形式:
var shoppingList = ["Eggs", "Milk"]
複製代碼
由於數組文字中的全部值都是相同類型的,Swift能夠推斷[String]是用於shoppingList變量的正確類型。
能夠經過數組的方法和屬性或下標語法訪問和修改數組。
要找出數組中的項數,請檢查它的只讀計數屬性:
print("The shopping list contains \(shoppingList.count) items.")
// Prints "The shopping list contains 2 items."
複製代碼
使用布爾屬性isEmpty做爲檢查計數屬性是否等於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."
複製代碼
你能夠經過調用數組的append(_:)方法在數組的末尾添加一個新項:
shoppingList.append("Flour")
// shoppingList now contains 3 items, and someone is making pancakes
複製代碼
或者,使用加法賦值操做符(+=)附加一個包含一個或多個兼容項的數組:
shoppingList += ["Baking Powder"]
// shoppingList now contains 4 items
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList now contains 7 items
複製代碼
使用下標語法從數組中檢索一個值,在數組名稱後的方括號中傳遞你想要檢索的值的索引:
var firstItem = shoppingList[0]
// firstItem is equal to "Eggs"
複製代碼
注意 數組中的第一項索引爲0,而不是1。Swift中的數組老是零索引的。
在給定的索引,您可使用下標語法改變現有的值:
shoppingList[0] = "Six eggs"
// the first item in the list is now equal to "Six eggs" rather than "Eggs"
複製代碼
當使用下標語法時,指定的索引必須是有效的。例如,寫入shoppingList[shoppingList]。試圖將一個項追加到數組的末尾會致使運行時錯誤。
您還可使用下標語法一次性更改一個值範圍,即便替換值集的長度與要替換的範圍不一樣。下面的例子將「巧克力醬」、「奶酪」和「黃油」替換爲「香蕉」和「蘋果」:
shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList now contains 6 items
複製代碼
要在數組指定的下標處插入一個項,能夠調用數組的insert(_:at:)方法:
shoppingList.insert("Maple Syrup", at: 0)
// shoppingList now contains 7 items
// "Maple Syrup" is now the first item in the list
複製代碼
這個對insert(_:at:)方法的調用將在購物列表的最開始插入一個值爲「Maple Syrup」的新項目,該值由索引0表示。
相似地,使用remove(at:)方法從數組中刪除一個項。這個方法移除指定索引處的項並返回被移除的項(儘管若是你不須要它,你能夠忽略返回值):
let mapleSyrup = shoppingList.remove(at: 0)
// the item that was at index 0 has just been removed
// shoppingList now contains 6 items, and no Maple Syrup
// the mapleSyrup constant is now equal to the removed "Maple Syrup" string
複製代碼
注意 若是試圖訪問或修改數組現有邊界以外的索引值,將觸發運行時錯誤。在使用索引以前,能夠經過將其與數組的count屬性進行比較來檢查索引是否有效。數組中最大的有效索引是count - 1,由於數組的索引是從0開始的。可是,當count爲0(意味着數組爲空)時,就沒有有效索引了。
當移除一個元素時,數組中的任何間隙都被關閉,所以索引0處的值再次等於「Six eggs」:
firstItem = shoppingList[0]
// firstItem is now equal to "Six eggs"
複製代碼
若是但願從數組中刪除最後一項,請使用removeLast()方法而不是remove(at:)方法來避免查詢數組的count屬性。與remove(at:)方法同樣,removeLast()返回被刪除的項:
let apples = shoppingList.removeLast()
// the last item in the array has just been removed
// shoppingList now contains 5 items, and no apples
// the apples constant is now equal to the removed "Apples" string
複製代碼
你能夠用for-in循環遍歷數組中的全部值:
for item in shoppingList {
print(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas
複製代碼
若是須要每一個項的整數索引及其值,則使用枚舉()方法迭代數組。對於數組中的每一個項,枚舉()方法返回由整數和項組成的元組。整數從0開始,每一項加1;若是枚舉整個數組,則這些整數與項的索引匹配。您能夠分解元組爲臨時常量或變量做爲迭代的一部分:
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
複製代碼
有關For-in循環的更多信息,請參見For-in循環。
集合在沒有定義順序的集合中存儲相同類型的不一樣值。若是項的順序不重要,或者須要確保項只出現一次,則可使用集合而不是數組。
注意
Swift的Set類型被橋接到Foundation的NSSet類。 有關在Foundation和Cocoa中使用Set的更多信息,請參見Set和NSSet之間的橋接。
爲了存儲在集合中,類型必須是可hashable的——也就是說,類型必須提供一種爲自身計算哈希值的方法。散列值是一個整型值,它對全部相等比較的對象都是相同的,這樣,若是A == b,就是A.hashValue == b.hashValue。
默認狀況下,Swift的全部基本類型(好比字符串、Int、Double和Bool)都是hashable的,能夠用做設置值類型或字典鍵類型。默認狀況下,沒有關聯值(如枚舉中所述)的枚舉用例值也是可hashable的。
注意
經過使它們符合Swift標準庫中的Hashable協議,您可使用本身的自定義類型做爲設置值類型或字典鍵類型。符合Hashable協議的類型必須提供一個可獲取的Int屬性hashValue。類型的hashValue屬性返回的值沒必要在同一程序的不一樣執行中或在不一樣程序中相同。
由於Hashable協議符合Equatable,符合的類型也必須提供equals操做符(==)的實現。可Equatable協議要求任何符合==的實現都是等價關係。也就是說,對於全部的a、b、c值,==的實現必須知足如下三個條件:
- a == b(自反性)
- a == b意味着b == a(對稱)
- a == b && b == c意味着a == c(傳遞性)
有關遵照協議的更多信息,請參見協議。
Swift集合的類型寫爲set
能夠用初始化器建立特定類型的空集合
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."
複製代碼
注意
根據初始化器的類型,推斷字母變量的類型設置爲。
或者,若是上下文已經提供了類型信息,好比函數參數或已經類型化的變量或常量,你能夠建立一個空數組文字:
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>
複製代碼
還能夠用數組文字初始化set,這是將一個或多個值編寫爲set集合的一種速記方法。
下面的例子建立了一個名爲favoritegenre的集合來存儲字符串值:
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres has been initialized with three initial items
複製代碼
favoritegenre變量被聲明爲「一組字符串值」,寫成set 。由於這個特殊的集合指定了字符串的值類型,因此只容許存儲字符串值。在這裏,favoritegenre設置用三個字符串值(「Rock」、「Classical」和「Hip hop」)初始化,用一個數組文字編寫。
注意
favoritegenre設置被聲明爲一個變量(用var導入器)而不是一個常量(用let導入器),由於在下面的例子中會添加和刪除條目。
不能僅從數組文字推斷集合類型,所以必須顯式聲明類型集。可是,因爲Swift的類型推斷,若是使用只包含一種類型值的數組文字初始化集合,則沒必要編寫集合元素的類型。初始化的favoritegenre能夠寫在一個更短的形式代替:
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
複製代碼
由於數組文字中的全部值都是相同類型的,Swift能夠推斷Set是favoritegenre變量使用的正確類型。
經過集合的方法和屬性訪問和修改集合。
要找出一個集合中的項數,請檢查它的只讀計數屬性:
print("I have \(favoriteGenres.count) favorite music genres.")
// Prints "I have 3 favorite music genres."
複製代碼
使用布爾屬性isEmpty做爲檢查計數屬性是否等於0的快捷方式:
if favoriteGenres.isEmpty {
print("As far as music goes, I'm not picky.")
} else {
print("I have particular music preferences.")
}
// Prints "I have particular music preferences."
複製代碼
你能夠經過調用集合的insert(_:)方法向集合中添加新項:
favoriteGenres.insert("Jazz")
// favoriteGenres now contains 4 items
複製代碼
您能夠經過調用集合的remove(_:)方法從集合中刪除一個項,若是該項是集合的成員,該方法將刪除該項,並返回刪除的值,若是集合不包含該值,則返回nil。或者,可使用其removeAll()方法刪除集合中的全部項。
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."
複製代碼
若要檢查集合是否包含特定項,請使用contains(_:)方法。
if favoriteGenres.contains("Funk") {
print("I get up on the good foot.")
} else {
print("It's too funky in here.")
}
// Prints "It's too funky in here."
複製代碼
可使用for-in循環遍歷集合中的值。
for genre in favoriteGenres {
print("\(genre)")
}
// Classical
// Jazz
// Hip hop
複製代碼
有關For- in循環的更多信息,請參見For-In Loops。
Swift的Set類型沒有定義的順序。要按特定順序遍歷集合的值,可使用sorted()方法,該方法將集合的元素做爲數組返回,並使用<操做符排序。
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
// Classical
// Hip hop
// Jazz
複製代碼
您能夠高效地執行基本的集合操做,例如將兩個集合組合在一塊兒,肯定兩個集合有哪些相同的值,或者肯定兩個集合是否包含全部相同的值、一些值或不包含相同的值。
下圖描述了兩個集合(a和b),它們是由陰影區域表示的各類集合操做的結果。
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]
複製代碼
下圖描繪了三個集合(a,b和c),其中重疊的區域表示集合之間共享的元素。 集a是集b的超集,由於a包含b中的全部元素。 相反,集合b是集合a的子集,由於b中的全部元素也都包含在a中。 集b和集c彼此不交集,由於它們沒有共同的元素。
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true
複製代碼
字典在沒有定義順序的狀況下將相同類型的鍵和相同類型的值之間的關聯存儲在集合中。 每一個值都與惟一鍵相關聯,該鍵充當字典中該值的標識符。 與數組中的項目不一樣,字典中的項目沒有指定的順序。 當您須要根據其標識符查找值時,可使用字典,這與使用現實世界詞典查找特定單詞的定義的方式幾乎相同。
注意
Swift的「字典」類型橋接到Foundation的NSDictionary類。
有關在Foundation和Cocoa中使用Dictionary的更多信息,請參見在Dictionary和NSDictionary之間架橋。
Swift字典的類型全寫爲Dictionary <Key,Value>,其中Key是可用做字典鍵的值的類型,Value是字典爲這些鍵存儲的值的類型。
注意
字典鍵類型必須符合哈希協議,例如集合的值類型。
您還能夠將簡寫形式的字典類型寫爲[Key:Value]。 儘管這兩種形式在功能上是相同的,但速記形式是首選,在引用字典類型時在本指南中使用。
和數組同樣,能夠用初始化語法建立一個特性類型的空字典:
var namesOfIntegers = [Int: String]()
// namesOfIntegers is an empty [Int: String] dictionary
複製代碼
上面例子建立一個[Int: String]類型的字典,key的類型是Int,value的類型是String
若是上下文已經提供了類型信息,則可使用空字典文字建立一個空字典,該文字以[:]書寫(一對方括號內的冒號):
namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]
複製代碼
您還可使用字典文字來初始化字典,該字典文字的語法與前面看到的數組文字類似。 字典文字是將一個或多個鍵值對編寫爲字典集合的一種簡便方法。
key-value是鍵和值的組合。 在字典文字中,每一個鍵值對中的鍵和值都用冒號分隔。 鍵值對以列表形式寫入,並用逗號分隔,並用方括號包圍:
[key 1: value 1, key 2: value 2, key 3: value 3]
複製代碼
下面的示例建立一個字典來存儲國際機場的名稱。 在此字典中,鍵是三個字母的國際航空運輸協會代碼,值是機場名稱:
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
複製代碼
airports被聲明爲一個[String: String]類型的字典,意味着字典的key是String類型,value也是String類型。
注意
airports被聲明爲一個變量(用var修飾),而不是常量(用let修飾),由於在下面的例子中須要新增數據進去。
airports用字典文字被初始化爲包含兩個鍵值對的字典。第一個key值是「YYZ」,value值是「Toronto Pearson」。第二個key值是「DUB」,value值是「Dublin」。
這個字典包含兩個String: String鍵值對,鍵值對的類型須要匹配airports聲明時的類型(key和value只能是String類型),所以,容許使用字典文字進行分配,以做爲初始化帶有兩個初始項的airports字典的一種方式。
與數組同樣,若是使用其鍵和值具備一致類型的字典文字來初始化字典,則沒必要編寫字典的類型。 airports的初始化原本能夠寫成較短的形式:
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
複製代碼
由於文字中的全部鍵彼此都具備相同的類型,而且全部值也都具備相同的類型,因此Swift能夠推斷[String:String]是用於airports字典的正確類型。
您能夠經過其方法和屬性或使用下標語法來訪問和修改字典。
與數組同樣,您能夠經過檢查字典的只讀count屬性來找出字典中的項目數:
print("The airports dictionary contains \(airports.count) items.")
// Prints "The airports dictionary contains 2 items."
複製代碼
使用布爾值isEmpty屬性做爲檢查count屬性是否等於0的快捷方式:
if airports.isEmpty {
print("The airports dictionary is empty.")
} else {
print("The airports dictionary is not empty.")
}
// Prints "The airports dictionary is not empty."
複製代碼
您可使用下標語法將新項目添加到字典中。 使用適當類型的新鍵做爲下標索引,並分配適當類型的新值:
airports["LHR"] = "London"
// the airports dictionary now contains 3 items
複製代碼
您還可使用下標語法來更改與特定鍵關聯的值:
airports["LHR"] = "London Heathrow"
// the value for "LHR" has been changed to "London Heathrow"
複製代碼
除了下標以外,還可使用字典的updateValue(:forKey :)方法來設置或更新特定鍵的值。 像上面的下標示例同樣,若是不存在鍵,則updateValue(:forKey :)方法將設置鍵的值;若是該鍵已存在,則更新該值。 可是,與下標不一樣,updateValue(_:forKey :)方法在執行更新後會返回舊值。 這使您能夠檢查是否進行了更新。
updateValue(_:forKey :)方法返回字典值類型的可選值。 例如,對於存儲字符串值的字典,該方法返回類型爲String?或「可選的字符串」的值。 若是更新以前存在一箇舊值,則此可選值包含該鍵的舊值;若是不存在任何值,則爲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."
複製代碼
您還可使用下標語法從字典中檢索特定鍵的值。 因爲能夠請求不存在任何值的鍵,所以字典的下標會返回字典值類型的可選值。 若是字典中包含所請求鍵的值,則下標將返回一個可選值,其中包含該鍵的現有值。 不然,下標返回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."
複製代碼
您可使用下標語法經過爲該鍵分配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."
複製代碼
您可使用for-in循環遍歷字典中的鍵/值對。 字典中的每一項都做爲(鍵,值)元組返回,而且您能夠在迭代過程當中將元組的成員分解爲臨時常量或變量:
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
// LHR: London Heathrow
// YYZ: Toronto Pearson
複製代碼
關於更多For-in循環,請參見For-In Loops
您還能夠經過訪問字典的鍵或值屬性來檢索字典的鍵或值的可迭代集合:
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}
// Airport code: LHR
// Airport code: YYZ
for airportName in airports.values {
print("Airport name: \(airportName)")
}
// Airport name: London Heathrow
// Airport name: Toronto Pearson
複製代碼
若是您須要經過帶有Array實例的API使用字典的鍵或值,請使用keys或values屬性初始化一個新數組:
let airportCodes = [String](airports.keys)
// airportCodes is ["LHR", "YYZ"]
let airportNames = [String](airports.values)
// airportNames is ["London Heathrow", "Toronto Pearson"]
複製代碼
Swift的Dictionary類型沒有定義的順序。 若要以特定順序遍歷字典的鍵或值,請在其鍵或值屬性上使用sorted()方法。
這篇文章主要涉及到集合的相關內容:包括數組,集合和字典。集合的初始化、訪問和修改以及遍歷,這些是集合的基本操做,經過閱讀上面的內容,相信你們對它們會有個熟悉的印象;配合代碼編寫,您將會有更深的印象。集合這個數據結構在咱們項目開發過程當中,也會頻繁被用到,因此須要熟練掌握它的用法。
最後,喜歡的朋友能夠給個👍哦,你的鼓勵就是個人動力,嘿嘿~
參考文檔: Swift - Collection Types