標籤:集合 數組 字典 儲存
IOS開發語言Swift入門連載—集合類型
Swift語言提供經典的數組和字典兩種集合類型來儲存集合資料。數組用來按順序儲存相同類型的資料。字典雖然無序儲存相同類型資料值但是需要由專屬的標識符引用和定址(就是索引值對)。
Swift語言裡的數組和字典中儲存的資料實值型別必須明確。 這意味著我們不能把不正確的資料類型插入其中。 同時這也說明我們完全可以對擷取出的實值型別非常自信。 Swift 對顯式類型集合的使用確保了我們的代碼對工作所需要的類型非常清楚,也讓我們在開發中可以早早地找到任何的類型不符錯誤。
注意:
Swift的數組結構在被聲明成常量和變數或者被傳入函數與方法中時會相對於其他類型展現出不同的特性。 擷取更多資訊請參見集合的可變性與集合在賦值和複製中的行為章節。
數組
數組使用有序列表格儲存體同一類型的多個值。相同的值可以多次出現在一個數組的不同位置中。
Swift數組特定於它所儲存元素的類型。這與 Objective-C 的 NSArray 和 NSMutableArray 不同,這兩個類可以儲存任意類型的對象,並且不提供所返回對象的任何特別資訊。在 Swift 中,資料值在被儲存進入某個數組之前類型必須明確,方法是通過顯式的類型標註或類型推斷,而且不是必須是class 類型。例如: 如果我們建立了一個Int 實值型別的數組,我們不能往其中插入任何不是Int 類型的資料。 Swift 中的數組是型別安全的,並且它們中包含的類型必須明確。
數組的簡單文法
寫 Swift 數組應該遵循像Array 這樣的形式,其中SomeType 是這個數組中唯一允許存在的資料類型。 我們也可以使用像SomeType[] 這樣的簡單文法。 儘管兩種形式在功能上是一樣的,但是推薦較短的那種,而且在本文中都會使用這種形式來使用數組。
數組構造語句
我們可以使用字面量來進行數組構造,這是一種用一個或者多個數值構造數組的簡單方法。字面量是一系列由逗號分割並由方括弧包含的數值。 [value 1, value 2, value 3] 。
下面這個例子建立了一個叫做shoppingList 並且儲存字串的數組:
var shoppingList: String[] = ["Eggs", "Milk"]// shoppingList 已經被構造並且擁有兩個初始項。
shoppingList變數被聲明為“字串實值型別的數組”,記作String[] 。 因為這個數組被規定只有String 一種資料結構,所以只有String 類型可以在其中被存取。 在這裡,shoppinglist 數組由兩個String 值(”Eggs” 和”Milk” )構造,並且由字面量定義。 注意: shoppingList數組被聲明為變數(var 關鍵字建立)而不是常量(let 建立)是因為以後可能會有更多的資料項目被插入其中。 在這個例子中,字面量僅僅包含兩個String 值。匹配了該數組的變數聲明(只能包含String 的數組),所以這個字面量的分配過程就是允許用兩個初始項來構造shoppinglist 。 由於 Swift 的類型推斷機制,當我們用字面量構造只擁有相同類型值數組的時候,我們不必把數組的類型定義清楚。 shoppinglist 的構造也可以這樣寫:
var shoppingList = ["Eggs", "Milk"]
因為所有字面量中的值都是相同的類型,Swift 可以推斷出String[] 是shoppinglist 中變數的正確類型。 訪問和修改數組 我們可以通過數組的方法和屬性來訪問和修改數組,或者下標文法。 還可以使用數組的唯讀屬性count 來擷取數組中的資料項目數量。
println("The shopping list contains \(shoppingList.count) items.")// 輸出"The shopping list contains 2 items."(這個數組有2個項)
使用布爾項isEmpty 來作為檢查count t屬性的值是否為 0 的捷徑。
if shoppingList.isEmpty { println("The shopping list is empty.")} else { println("The shopping list is not empty.")}// 列印 "The shopping list is not empty."(shoppinglist不是空的)
也可以使用 append 方法在數組後面添加新的資料項目:
shoppingList.append("Flour")// shoppingList 現在有3個資料項目,有人在攤煎餅
除此之外,使用加法賦值運算子(+= )也可以直接在數組後面添加資料項目:
shoppingList += "Baking Powder"// shoppingList 現在有四項了
我們也可以使用加法賦值運算子(+= )直接添加擁有相同類型資料的數組。
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]// shoppingList 現在有7項了
可以直接使用下標文法來擷取數組中的資料項目,把我們需要的資料項目的索引值放在直接放在數組名稱的方括弧中:
var firstItem = shoppingList[0]// 第一項是 "Eggs"
注意第一項在數組中的索引值是0 而不是1 。 Swift 中的數組索引總是從零開始。 我們也可以用下標來改變某個已有索引值對應的資料值:
shoppingList[0] = "Six eggs"// 其中的第一項現在是 "Six eggs" 而不是 "Eggs"
還可以利用下標來一次改變一系列資料值,即使新資料和原有資料的數量是不一樣的。下面的例子把”Chocolate Spread” ,”Cheese” ,和”Butter” 替換為”Bananas” 和 “Apples” :
shoppingList[4...6] = ["Bananas", "Apples"]// shoppingList 現在有六項
注意: 我們不能使用下標文法在數組尾部添加新項。如果我們試著用這種方法對索引越界的資料進行檢索或者設定新值的操作,我們會引發一個運行期錯誤。我們可以使用索引值和數組的count 屬性進行比較來在使用某個索引之前先檢驗是否有效。除了當count 等於 0 時(說明這是個空數組),最大索引值一直是count - 1 ,因為數組都是零起索引。 調用數組的insert(atIndex 方法來在某個具體索引值之前添加資料項目:
shoppingList.insert("Maple Syrup", atIndex: 0)// shoppingList 現在有7項// "Maple Syrup" 現在是這個列表中的第一項
這次insert 函數調用把值為”Maple Syrup” 的新資料項目插入列表的最開始位置,並且使用0 作為索引值。 類似的我們可以使用removeAtIndex 方法來移除數組中的某一項。這個方法把數組在特定索引值中儲存的資料項目移除並且返回這個被移除的資料項目(我們不需要的時候就可以無視它):
let mapleSyrup = shoppingList.removeAtIndex(0)// 索引值為0的資料項目被移除// shoppingList 現在只有6項,而且不包括Maple Syrup// mapleSyrup常量的值等於被移除資料項目的值 "Maple Syrup"
資料項目被移除後數組中的空出項會被自動填補,所以現在索引值為0 的資料項目的值再次等於”Six eggs”:
firstItem = shoppingList[0]// firstItem 現在等於 "Six eggs"
如果我們只想把數組中的最後一項移除,可以使用removeLast 方法而不是removeAtIndex 方法來避免我們需要擷取數組的count 屬性。就像後者一樣,前者也會返回被移除的資料項目:
let apples = shoppingList.removeLast()// 數組的最後一項被移除了// shoppingList現在只有5項,不包括cheese// apples 常量的值現在等於"Apples" 字串
數組的遍曆 我們可以使用for-in迴圈來遍曆所有數組中的資料項目: 如果我們同時需要每個資料項目的值和索引值,可以使用全域enumerate 函數來進行數組遍曆。enumerate 返回一個由每一個資料項目索引值和資料值組成的元組。我們可以把這個元組分解成臨時常量或者變數來進行遍曆:
for (index, value) in enumerate(shoppingList) { println("Item \(index + 1): \(value)")}// Item 1: Six eggs// Item 2: Milk// Item 3: Flour// Item 4: Baking Powder// Item 5: Bananas
更多關於for-in 迴圈的介紹請參見for 迴圈。 建立並且構造一個數組 我們可以使用構造文法來建立一個由特定資料類型構成的空數組: 注意someInts 被設定為一個Int[] 建構函式的輸出所以它的變數類型被定義為Int[] 。 除此之外,如果代碼上下文中提供了類型資訊, 例如一個函數參數或者一個已經定義好類型的常量或者變數,我們可以使用空數組語句建立一個空數組,它的寫法很簡單:[] (一對空方括弧):
someInts.append(3)// someInts 現在包含一個INT值someInts = []// someInts 現在是空數組,但是仍然是Int[]類型的。
Swift中的Array 類型還提供一個可以建立特定大小並且所有資料都被預設的構造方法。我們可以把準備加入新數組的資料項目數量(count )和適當類型的初始值(repeatedValue )傳入數組建構函式:
var threeDoubles = Double[](count: 3, repeatedValue:0.0)// threeDoubles 是一種 Double[]數組, 等於 [0.0, 0.0, 0.0]
因為類型推斷的存在,我們使用這種構造方法的時候不需要特別指定數組中儲存的資料類型,因為類型可以從預設值推斷出來:
var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5)// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5]
最後,我們可以使用加法操作符(+ )來組合兩種已存在的相同類型數組。新數組的資料類型會被從兩個數組的資料類型中推斷出來:
var sixDoubles = threeDoubles + anotherThreeDoubles// sixDoubles 被推斷為 Double[], 等於 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
字典
字典是一種儲存多個相同類型的值的容器。每個值(value)都關聯唯一的鍵(key),鍵作為字典中的這個值資料的標識符。和數組中的資料項目不同,字典中的資料項目並沒有具體順序。我們在需要通過標識符(鍵)訪問資料的時候使用字典,這種方法很大程度上和我們在現實世界中使用字典查字義的方法一樣。 Swift 的字典使用時需要具體規定可以儲存鍵和實值型別。不同於 Objective-C 的NSDictionary 和NSMutableDictionary 類可以使用任何類型的對象來作鍵和值並且不提供任何關於這些對象的本質資訊。在 Swift 中,在某個特定字典中可以儲存的鍵和值必須提前定義清楚,方法是通過顯性類型標註或者類型推斷。 Swift的字典使用Dictionary
[key 1: value 1, key 2: value 2, key 3: value 3]
下面的例子建立了一個儲存國際機場名稱的字典。在這個字典中鍵是三個字母的國際航空運輸相關代碼,值是機場名稱:
var airports: Dictionary<String, String> = ["TYO": "Tokyo", "DUB": "Dublin"]
airports字典被定義為一種Dictionary 它意味著這個字典的鍵和值都是String 類型。 注意: airports字典被聲明為變數(用var 關鍵字)而不是常量(let 關鍵字)因為後來更多的機場資訊會被添加到這個樣本字典中。 airports字典使用字典字面量初始化,包含兩個索引值對。第一對的鍵是TYO ,值是Tokyo 。第二對的鍵是DUB ,值是Dublin 。 這個字典語句包含了兩個String: String 類型的索引值對。它們對應airports 變數聲明的類型(一個只有String 鍵和String 值的字典)所以這個字典字面量是構造兩個初始資料項目的airport 字典。 和數組一樣,如果我們使用字面量構造字典就不用把類型定義清楚。airports 的也可以用這種方法簡短定義:
var airports = ["TYO": "Tokyo", "DUB": "Dublin"]
因為這個語句中所有的鍵和值都分別是相同的資料類型,Swift 可以推斷出Dictionary 是airports 字典的正確類型。 讀取和修改字典 我們可以通過字典的方法和屬性來讀取和修改字典,或者使用下標文法。和數組一樣,我們可以通過字典的唯讀屬性count 來擷取某個字典的資料項目數量:
println("The dictionary of airports contains \(airports.count) items.")// 列印 "The dictionary of airports contains 2 items."(這個字典有兩個資料項目)
我們也可以在字典中使用下標文法來添加新的資料項目。可以使用一個合適類型的 key 作為下標索引,並且分配新的合適類型的值:
airports["LHR"] = "London"// airports 字典現在有三個資料項目
我們也可以使用下標文法來改變特定鍵對應的值:
airports["LHR"] = "London Heathrow"// "LHR"對應的值 被改為 "London Heathrow
作為另一種下標方法,字典的updateValue(forKey 方法可以設定或者更新特定鍵對應的值。就像上面所示的樣本,updateValue(forKey 方法在這個鍵不存在對應值的時候設定值或者在存在時更新已存在的值。和上面的下標方法不一樣,這個方法返回更新值之前的原值。這樣方便我們檢查更新是否成功。 updateValue(forKey函數會返回包含一個字典實值型別的可選值。舉例來說:對於儲存String 值的字典,這個函數會返回一個String? 或者“可選 String ”類型的值。如果值存在,則這個可選值值等於被替換的值,否則將會是nil 。
if let oldValue = airports.updateValue("Dublin Internation", forKey: "DUB") { println("The old value for DUB was \(oldValue).")}// 輸出 "The old value for DUB was Dublin."(DUB原值是dublin)
我們也可以使用下標文法來在字典中檢索特定鍵對應的值。由於使用一個沒有值的鍵這種情況是有可能發生的,可選類型返回這個鍵存在的相關值,否則就返回nil :
if let airportName = airports["DUB"] { println("The name of the airport is \(airportName).")} else { println("That airport is not in the airports dictionary.")}// 列印 "The name of the airport is Dublin Internation."(機場的名字是都柏林國際)
我們還可以使用下標文法來通過給某個鍵的對應值賦值為nil 來從字典裡移除一個索引值對:
airports["APL"] = "Apple Internation"// "Apple Internation"不是真的 APL機場, 刪除它airports["APL"] = nil// APL現在被移除了
另外,removeValueForKey 方法也可以用來在字典中移除索引值對。這個方法在索引值對存在的情況下會移除該索引值對並且返回被移除的value或者在沒有值的情況下返回nil :
if let removedValue = airports.removeValueForKey("DUB") { println("The removed airport‘s name is \(removedValue).")} else { println("The airports dictionary does not contain a value for DUB.")}// prints "The removed airport‘s name is Dublin International."
字典遍曆
我們可以使用for-in 迴圈來遍曆某個字典中的索引值對。每一個字典中的資料項目都由(key, value) 元組形式返回,並且我們可以使用臨時常量或者變數來分解這些元組:
for (airportCode, airportName) in airports { println("\(airportCode): \(airportName)")}// TYO: Tokyo// LHR: London Heathrow
for-in迴圈請參見For 迴圈。 我們也可以通過訪問它的keys 或者values 屬性(都是可遍曆集合)檢索一個字典的鍵或者值:
for airportCode in airports.keys { println("Airport code: \(airportCode)")}// Airport code: TYO// Airport code: LHRfor airportName in airports.values { println("Airport name: \(airportName)")}// Airport name: Tokyo// Airport name: London Heathrow
如果我們只是需要使用某個字典的鍵集合或者值集合來作為某個接受Array 執行個體 API 的參數,可以直接使用keys 或者values 屬性直接構造一個新數組:
let airportCodes = Array(airports.keys)// airportCodes is ["TYO", "LHR"]let airportNames = Array(airports.values)// airportNames is ["Tokyo", "London Heathrow"]
注意:
Swift 的字典類型是無序集合類型。其中字典鍵,值,索引值對在遍曆的時候會重新排列,而且其中順序是不固定的。
建立一個空字典
我們可以像數組一樣使用構造文法建立一個空字典:
var namesOfIntegers = Dictionary<Int, String>()// namesOfIntegers 是一個空的 Dictionary<Int, String>
這個例子建立了一個Int, String 類型的空字典來儲存英語對整數的命名。它的鍵是Int 型,值是String 型。 如果上下文已經提供了資訊類型,我們可以使用空字典字面量來建立一個空字典,記作[:] (中括弧中放一個冒號):
namesOfIntegers[16] = "sixteen"// namesOfIntegers 現在包含一個索引值對namesOfIntegers = [:]// namesOfIntegers 又成為了一個 Int, String類型的空字典
注意:
在後台,Swift 的數組和字典都是由泛型集合來實現的,想瞭解更多泛型和集合資訊請參見泛型。
集合的可變性
數組和字典都是在單個集合中儲存可變值。如果我們建立一個數組或者字典並且把它分配成一個變數,這個集合將會是可變的。這意味著我們可以在建立之後添加更多或移除已存在的資料項目來改變這個集合的大小。與此相反,如果我們把數組或字典分配成常量,那麼它就是不可變的,它的大小不能被改變。
對字典來說,不可變性也意味著我們不能替換其中任何現有鍵所對應的值。不可變字典的內容在被首次設定之後不能更改。 不可變性對數組來說有一點不同,當然我們不能試著改變任何不可變數組的大小,但是我們可以重新設定相對現存索引所對應的值。這使得 Swift 數組在大小被固定的時候依然可以做的很棒。
數組的可變性行為同時影響了數組執行個體如何被分配和修改,想擷取更多資訊,請參見集合在賦值和複製中的行為。
注意:
在我們不需要改變數組大小的時候建立不可變數組是很好的習慣。如此 Swift 編譯器可以最佳化我們建立的集合。
IOS開發語言Swift入門連載---集合類型