# Swift中文教程(四) 集合類(lèi)型

由蘋(píng)果官網(wǎng)翻譯得來(lái)
fork自https://github.com/letsswift/The-Swift-Programming-Language-in-Chinese
https://github.com/TyrantDante/The-Swift-Programming-Language-in-Chinese 完善和檢查

Swift 提供三種集合類(lèi)型來(lái)存儲(chǔ)集合,數(shù)組,sets(集合)和字典。數(shù)組是一個(gè)同類(lèi)型的序列化列表集合。sets是特定類(lèi)型的無(wú)序集合。字典是一個(gè)能夠使用類(lèi)似于鍵的唯一標(biāo)識(shí)符來(lái)獲取值的非序列化集合。

CollectionTypes_intro_2x.png

在Swift中,數(shù)組,sets(集合)和字典里的鍵和值都必須是明確的某個(gè)特定類(lèi)型。這意味這數(shù)組和字典不會(huì)插入一個(gè)錯(cuò)誤的類(lèi)型的值,以致于出錯(cuò)。這也意味著當(dāng)你在數(shù)組和字典中取回?cái)?shù)值的時(shí)候能夠確定它的類(lèi)型。

Swift 使用確定的集合類(lèi)型可以保證代碼工作是不會(huì)出錯(cuò),和讓你在開(kāi)發(fā)階段就能更早的捕獲錯(cuò)誤。

swift中數(shù)組,set和字典被是實(shí)現(xiàn)成常用的集合,更多請(qǐng)關(guān)注Generics

可變集合

如果你創(chuàng)建了一個(gè)數(shù)組,set或者字典,并且申明他為變量,那么該集合就是可變的。這就意味著你可以通過(guò)添加、刪除或者改變他的item來(lái)改變這個(gè)集合。如果你申明了數(shù)組,set或者字典為常量,那么他就沒(méi)辦法修改。他的內(nèi)容和大小都沒(méi)法修改。

如果集合不需要修改,盡量申明成常量。這樣編譯器會(huì)優(yōu)化你的集合。

數(shù)組

數(shù)組是儲(chǔ)存同類(lèi)型多數(shù)值的序列化列表。同樣的值可以在數(shù)組的不同位置出現(xiàn)多次。

swift中的Array 是橋接自Foundation的NSArray。更多請(qǐng)關(guān)注Using Swift with Cocoa and Objective-C (Swift 2.2).

數(shù)組的簡(jiǎn)略語(yǔ)法

定義數(shù)組的完整寫(xiě)法是Array<SomeType>,其中SomeType是你想要包含的類(lèi)型。你也可以使用類(lèi)似于SomeType[]這樣的簡(jiǎn)略語(yǔ)法。雖然這兩種方法在功能上是相同的。但是我們更推薦后者,而且它會(huì)一直貫穿于本書(shū)。

創(chuàng)建一個(gè)空的數(shù)組

可以使用構(gòu)造語(yǔ)句來(lái)創(chuàng)建某些類(lèi)型的數(shù)組

var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// prints "someInts is of type [Int] with 0 items"

注意someInts在初始化時(shí)就被定義成int的數(shù)組,是無(wú)法添加其他類(lèi)型的。

如果數(shù)組已經(jīng)被制定了值類(lèi)型,你就可以通過(guò)‘[]’空的中括號(hào)創(chuàng)建一個(gè)空的數(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]

創(chuàng)建一個(gè)默認(rèn)數(shù)值的數(shù)組

swift中數(shù)組也可以創(chuàng)建并且出實(shí)話(huà)一個(gè)帶有默認(rèn)個(gè)數(shù)和相同的默認(rèn)值的數(shù)組。你傳遞給初始化函數(shù)數(shù)組個(gè)數(shù)(count)和一個(gè)合適類(lèi)型的默認(rèn)值(repeatedValue)

var threeDoubles = [Double](count:3,repeatedValue:0.0)
// threeDoubles is type [Double],and equals [0.0,0.0,0.0]

創(chuàng)建一個(gè)數(shù)組由其他兩個(gè)數(shù)組相加

最后,你可以使用(+)操作符就能創(chuàng)建一個(gè)新的數(shù)組,把兩個(gè)存在的數(shù)組添加進(jìn)來(lái)
這個(gè)新的數(shù)組類(lèi)型從你添加的兩個(gè)數(shù)組中推斷出來(lái)

var anotherThreeDoubles = [Double](count:3,repeatedValue:2.5)
// anotherThreeDoubles is of type [Double],and equals [2.5,2.5,2.5]
var sixDoubles = threeDouble + anotherThreeDoubles
// sixDoubles is inferred as [Double],and equals [0.0,0.0,0.0,2.5,2.5,2.5]

使用數(shù)組實(shí)量創(chuàng)建數(shù)組

你可以用一個(gè)數(shù)組實(shí)量(Array Literals)來(lái)初始化一個(gè)數(shù)組,它是用簡(jiǎn)略寫(xiě)法來(lái)創(chuàng)建一個(gè)包含一個(gè)或多個(gè)的值的數(shù)組。一個(gè)數(shù)組實(shí)量(Array Literals)是由它包含的值,“,”分隔符 已經(jīng)包括以上內(nèi)容的中括號(hào)對(duì)“[]”組成:

[value 1, value 2, value 3]

下面的例子是創(chuàng)建一個(gè)叫shoppinglist,儲(chǔ)存字符串(String)類(lèi)型的數(shù)組。

var shoppingList:[String] = ["Eggs", "Milk"]
// 使用兩個(gè)初始化參數(shù)來(lái)初始化shoppingList

shoppinglist變量被定義為字符串(String)類(lèi)型的數(shù)組,寫(xiě)作[String]。因?yàn)檫@個(gè)數(shù)組被確定為字符串類(lèi)型(String),所以它只能儲(chǔ)存字符串(String)類(lèi)型的值。在這里,我們用兩個(gè)字符串類(lèi)型的值(”Eggs” and “Milk”)和數(shù)組實(shí)量(Array Literals)的寫(xiě)法來(lái)初始化shoppingList數(shù)組。

注意
shoppingList數(shù)組是被定義為一個(gè)變量(使用var 標(biāo)識(shí)符)而不是常量(使用let 標(biāo)識(shí)符),所以在下面的例子可以直接添加元素。

在這個(gè)例子中,數(shù)組實(shí)量(Array Literals)只包含兩個(gè)字符串類(lèi)型的值,這符合了shoppingList變量的定義(只能包含字符串(String)類(lèi)型的數(shù)組),所以被分配的數(shù)組實(shí)量(Array Literals)被允許用兩個(gè)字符串類(lèi)型的值來(lái)初始化。

得益于Swift的類(lèi)型推斷,當(dāng)你用相同類(lèi)型的值來(lái)初始化時(shí),你可以不寫(xiě)明類(lèi)型。初始化shoppingList可以用下面這個(gè)方法來(lái)代替。

var shoppingList = ["Eggs", “Milk"]

因?yàn)閿?shù)組實(shí)量(Array Literals)中所有的值都是同類(lèi)型的,所以Swift能夠推斷shoppingList的類(lèi)型為字符串?dāng)?shù)組([String])。

讀取和修改數(shù)組

你可以通過(guò)方法和屬性,或者下標(biāo)來(lái)讀取和修改數(shù)組。

通過(guò)只讀屬性count來(lái)讀取數(shù)組的項(xiàng)數(shù);

print("The shopping list contains \(shoppingList.count) items.")
// 打印出 "The shopping list contains 2 items.”

通過(guò)一個(gè)返回布爾類(lèi)型的isEmpty屬性檢查數(shù)組的項(xiàng)數(shù)是否為0

if shoppingList.isEmpty {
    print("The shopping list is empty.")
} else {
    print("The shopping list is not empty.")
}
// 打印出 "The shopping list is not empty."

在數(shù)組末尾增加一項(xiàng)可以通過(guò)append方法

shoppingList.append("Flour")
// shoppingList 現(xiàn)在包含3項(xiàng)

同理,也可以用(+=)操作符來(lái)把一個(gè)元素添加到數(shù)組末尾

shoppingList += "Baking Powder"
// shoppingList 現(xiàn)在包含4項(xiàng)

你也可以用(+=)操作符來(lái)把一個(gè)數(shù)組添加到另一個(gè)數(shù)組的末尾

shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList 現(xiàn)在包含7個(gè)元素

從數(shù)組中取出一個(gè)值可以使用下標(biāo)語(yǔ)法。如果你知道一個(gè)元素的索引值,你可以數(shù)組名后面的中括號(hào)中填寫(xiě)索引值來(lái)獲取這個(gè)元素

var firstItem = shoppingList[0]
// firstItem 等于 “Eggs"

注意,數(shù)組的第一個(gè)元素的索引值為0,不為1,Swift的數(shù)組的索引總是從0開(kāi)始;

你可以使用下標(biāo)語(yǔ)法通過(guò)索引修改已經(jīng)存在的值。

shoppingList[0] = "Six eggs"
//列表中的第一個(gè)值等于"Six eggs" 而不等于 “Eggs"

你可以使用下標(biāo)語(yǔ)法一次性改變一系列的值,盡管修改的區(qū)域遠(yuǎn)遠(yuǎn)大于要修改的值。在下面的例子中, 把 “Chocolate Spread”, “Cheese”和”Butter”替換為”Bananas”和”Apples”:

shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList 現(xiàn)在包含6個(gè)元素

注意,你不能使用下標(biāo)語(yǔ)法在數(shù)組中添加一個(gè)元素,如果你嘗試使用下標(biāo)語(yǔ)法來(lái)獲取或者設(shè)置一個(gè)元素,你將得到一個(gè)運(yùn)行時(shí)的錯(cuò)誤。盡管如此,你可以通過(guò)count屬性驗(yàn)證索引是否正確再使用它。除非count等于0(也就是說(shuō)數(shù)組是空的),最大的索引都是count-1,因?yàn)閿?shù)組的索引從0開(kāi)始計(jì)算。

在一個(gè)特定的索引位置插入一個(gè)值,可以使用insert(atIndex:)方法

shoppingList.insert("Maple Syrup", atIndex: 0)
// shoppingList 現(xiàn)在包含7個(gè)元素
// "Maple Syrup" 在數(shù)組的第一位

這里調(diào)用insert方法指明在shoppingList的索引為0的位置中插入一個(gè)新元素 “Maple Syrup”

同理,你可以調(diào)用removeAtIndex方法移除特定的元素。這個(gè)方法移除特定索引位置的元素并返回這個(gè)被移除的元素(盡管你可能并不關(guān)心這個(gè)返回值)。

let mapleSyrup = shoppingList.removeAtIndex(0)
// 索引位置為0的元素被移除
// shoppingList 現(xiàn)在包含6個(gè)元素, 不包括 Maple Syrup
// mapleSyrup 常量等于被移除的 "Maple Syrup" 字符串

當(dāng)元素被移除的,數(shù)組空缺的位置將會(huì)被填補(bǔ),所以現(xiàn)在索引位置為0的元素再一次等于”Six eggs”:

firstItem = shoppingList[0]
// firstItem 現(xiàn)在等于 "Six eggs”

如果你想從數(shù)組中移除最后一個(gè)元素,使用removeLast方法比removeAtIndex更方便,因?yàn)楹笳咝枰ㄟ^(guò)count屬性計(jì)算數(shù)組的長(zhǎng)度。和removeAtIndex方法一樣,removeLast會(huì)返回被移除的元素。

let apples = shoppingList.removeLast()
//元素的最后一個(gè)元素被移除
// shoppingList 現(xiàn)在包含5個(gè)元素,不包括 cheese
// apples 常量 現(xiàn)在等于被移除的 "Apples" string

遍歷數(shù)組

可以使用for-in循環(huán)來(lái)遍歷數(shù)組中的值

for item in shoppingList {
    print(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas

如果既需要每個(gè)元素的值,又需要每個(gè)元素的索引值,使用enumerate函數(shù)代替會(huì)更方便,enumerate函數(shù)對(duì)于每一個(gè)元素都會(huì)返回一個(gè)包含元素的索引和值的元組(tuple)。你可以在遍歷部分分解元素并儲(chǔ)存在臨時(shí)變量或者常量中。

for (index, value) in enumerate(shoppingList) {
    print("Item \(index + 1): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas

如需更多for-in 循環(huán)信息, 參見(jiàn) For Loops.

Sets

一個(gè)集合存儲(chǔ)了一串無(wú)序的相同類(lèi)型的數(shù)據(jù)。如果對(duì)順序沒(méi)有要求,或者只是用一次的時(shí)候,可以使用set來(lái)替代數(shù)組。

swift set類(lèi)型橋接自Foundation中的NSSet類(lèi)
參見(jiàn)[Using Swift with Cocoa and Objective-C] (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216).

set類(lèi)型中的哈希值

儲(chǔ)存進(jìn)一個(gè)集合的類(lèi)型必須是可以哈?;?。該類(lèi)行必須提供一個(gè)方法來(lái)計(jì)算它本身的哈希值。哈希值是一個(gè)int值。所有相同的對(duì)象的哈希值是一樣的。如果a == b 的返回值和 a.hashValue == b.hashValue 的返回值是一樣的,
所有的swift基本類(lèi)型(String,Int,Double,Bool)默認(rèn)是可以哈希化的。而且可以用類(lèi)設(shè)置值類(lèi)型或者字典鍵類(lèi)型。沒(méi)有關(guān)聯(lián)值得枚舉值也是默認(rèn)可以哈?;?。

你可用使用自定義類(lèi)型來(lái)設(shè)置值類(lèi)型或字典類(lèi)型,自定義類(lèi)型需要從swift標(biāo)準(zhǔn)庫(kù)遵守哈?;瘏f(xié)議。遵守哈?;瘏f(xié)議的類(lèi)型必須提供一個(gè)叫做hashValue的方法(返回類(lèi)型為Int)。hashValue的值在不同的程序或相同的程序中返回不要求相同。
因?yàn)楣;瘏f(xié)議是可變的。遵守協(xié)議的類(lèi)型必須實(shí)現(xiàn)運(yùn)算符(== or ‘is equal’)。Equatable協(xié)議要求必須實(shí)現(xiàn)“==”成一個(gè)等價(jià)關(guān)系。見(jiàn)下面的例子
a == a (自反性)
a == b 相當(dāng)于 b == a(對(duì)稱(chēng)性)
a == b && b == c 相當(dāng)于 a == c (傳遞性)
查看相關(guān)protocol資料,詳見(jiàn)Protocols

集合類(lèi)型語(yǔ)法

集合類(lèi)型的語(yǔ)法是Set<Element>,Element是允許存入集合中的類(lèi)型。
更數(shù)組不同的是,集合沒(méi)有簡(jiǎn)便方法。

創(chuàng)建和初始化一個(gè)空集合

你可以通過(guò)某些類(lèi)型的構(gòu)造方法來(lái)創(chuàng)建一個(gè)空的集合

var letters = Set<Character>()
print("letters is if type Set<Character> with \(letters.count) items")
//Prints "letters is of type Set<Character> with 0 items."

letters變量的類(lèi)型是由Set<Character>的構(gòu)造器獲得。

如果上下文已經(jīng)提供了類(lèi)型信息,就可以通過(guò)設(shè)置一個(gè)空的數(shù)組實(shí)例來(lái)創(chuàng)建一個(gè)空的集合

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>

通過(guò)數(shù)組實(shí)例創(chuàng)建創(chuàng)建集合

你也可以通過(guò)一個(gè)數(shù)組實(shí)例創(chuàng)建集合。這是一個(gè)簡(jiǎn)寫(xiě)的方式寫(xiě)入一或多個(gè)值。
下面的例子,favoriteGenres 存儲(chǔ)多個(gè)string 值

var favoriteGenres:Set<String> = ["Rock","Classical","Hip hop"]
//favoriteGenres has been initialized with three initial items

favoriteGenres變量被定義成一個(gè)字符串的集合,寫(xiě)成Set<String>.因其指定了值類(lèi)型是字符創(chuàng),所以他只能儲(chǔ)存字符串的值,這里favoriteGenres被初始化并賦值成(“Rock”,“Classical” ,“Hip hop”).

集合類(lèi)型不能從數(shù)組常量中推斷出來(lái),所以集合類(lèi)型中Set關(guān)鍵字必須加上。結(jié)合swfit的特性,用包含值得數(shù)組實(shí)例初始化的話(huà),你不需要寫(xiě)集合包含的類(lèi)型。favoriteGenres可以被簡(jiǎn)寫(xiě)成這樣:

var favoriteGenres:Set = ["Rock","Classical","Hip hop"]

因?yàn)閿?shù)組實(shí)例中的所有值都是一個(gè)類(lèi)型,swift可以推斷出一個(gè)正確的類(lèi)型給favoriteGenres變量,為Set<String>

訪問(wèn)和修改一個(gè)集合

可以通過(guò)集合的方法和屬性來(lái)訪問(wèn)和改變他
獲取一個(gè)set的item數(shù)量,使用它的只讀屬性count

print("I have \(favoriteGenres.count) favorite music genres.")
// Prints "I have 3 favorite music genres."

使用布爾類(lèi)型的isEmpty 快捷的檢查他的count是不是 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(_:)方法添加一個(gè)item

favoriteGenres.insert("Jazz")
// favoriteGenres nw contains 4 items

通過(guò) remove(_:)方法來(lái)刪除一個(gè)item,如果集合擁有這個(gè)item,返回被remove的值,如果沒(méi)有返回nil,當(dāng)然可以用 removeAll方法移除所有的items

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."

通過(guò)contains(_:)方法來(lái)檢查集合是否包含該item

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來(lái)遍歷集合的所有值

for genre in favoriteGenres {
    print("\(genre)")
}
// Classical
// Jazz
// Hip hop

執(zhí)行集合操作

您可以有效地執(zhí)行基本設(shè)置操作,如結(jié)合兩套在一起,確定哪些值兩組的共同點(diǎn),或決定是否兩套包含所有,或沒(méi)有一個(gè)相同的值。

基本的集合操作

下面的說(shuō)明描述了兩個(gè)集合(a,b)各種集合操作的結(jié)果所代表的陰影區(qū)域。


setVennDiagram_2x.png
  1. intersect(_:)方法:返回兩個(gè)集合都擁有的元素的集合,

  2. exclusiverOr(_:)方法:返回兩個(gè)集合去除都擁有的元素后的所有的元素的集合

  3. union(_:)方法:返回兩個(gè)集合的所有元素的集合

  4. subtract(_:)方法:返回去除目標(biāo)集合中另一個(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).sort()
    // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    oddDigits.intersect(evenDigits).sort()
    // []
    oddDigits.subtract(singleDigitPrimeNumbers).sort()
    // [1, 9]
    oddDigits.exclusiveOr(singleDigitPrimeNumbers).sort()
    // [1, 2, 9]

集合之間的項(xiàng)目關(guān)系和相等

下面的插圖描述了三個(gè)集合a,b和c和重疊區(qū)域代表元素集之間共享。設(shè)置a是b的超集,因?yàn)榘怂性豣。相反地,b是a的一個(gè)子集,因?yàn)樗性豣也包含于a。b,c是不相交的,因?yàn)樗麄儧](méi)有共同之處。


setEulerDiagram_2x.png
  1. "=="(is equal)方法:判斷兩個(gè)集合是否擁有相同的元素,相同返回true,反之false

  2. isSubsetOf(_:)方法:判斷目標(biāo)集合是是否為參數(shù)集合的子集,是則返回true,反之false

  3. isSupersetOf(_:)方法:判斷目標(biāo)集合是否為參數(shù)集合的超集,是則返回true,反之false

  4. isStrictSubsetOf(_:)和isStrictSupersetOf(_:)方法:判斷目標(biāo)是否是子集和超集,但是必須是兩個(gè)集合不相等,滿(mǎn)足以上條件返回true,反之false

  5. isDisjointWith(_:)方法:判斷兩個(gè)集合有無(wú)相同元素,有相同元素則返回false,反之true。

    let houseAnimals: Set = ["??", "??"]
    let farmAnimals: Set = ["??", "??", "??", "??", "??"]
    let cityAnimals: Set = ["??", "??"]

    houseAnimals.isSubsetOf(farmAnimals)
    // true
    farmAnimals.isSupersetOf(houseAnimals)
    // true
    farmAnimals.isDisjointWith(cityAnimals)
    // true

字典

字典是儲(chǔ)存同一類(lèi)型多個(gè)值的容器。每一個(gè)值都對(duì)應(yīng)這一個(gè)唯一的鍵(Key),就像是字典內(nèi)的每一個(gè)值都有一個(gè)標(biāo)識(shí)符。和數(shù)組內(nèi)的元素是有區(qū)別的,字典內(nèi)的元素是沒(méi)有特殊的序列的。當(dāng)你需要根據(jù)標(biāo)識(shí)符來(lái)查找批量的值時(shí),就可以使用字典,和在真實(shí)世界的字典中尋找某個(gè)字的解釋相似。

Swift字典儲(chǔ)存一個(gè)特定類(lèi)型的鍵和值,與Objective-C的NSDictionary 和NSMutableDictionary不同,因?yàn)樗鼈兪鞘褂酶鞣N的對(duì)象來(lái)作為它們的鍵和值,而且并不提供任何有關(guān)對(duì)象的具體信息。在Swift中,對(duì)于一個(gè)特定的字典,它所能儲(chǔ)存的鍵和值的類(lèi)型都是確定的,無(wú)論是明確聲明的類(lèi)型還是隱式推斷的類(lèi)型。

Swift的字典寫(xiě)法是Dictionary<KeyType,ValueType>,KeyType是你想要儲(chǔ)存的鍵的類(lèi)型,ValueType是你想要儲(chǔ)存的值的類(lèi)型。

唯一的限制就是KeyType必須是可哈希的(hashable)——就是提供一個(gè)形式讓它們自身是獨(dú)立識(shí)別的。Swift的所有基礎(chǔ)類(lèi)型(例如字符串(String),整形(Int),雙精度(Double)和布爾(Bool))在默認(rèn)是可哈希的(hashable),和這些類(lèi)型都常常被當(dāng)作字典的鍵。沒(méi)有協(xié)助值(associated values)的枚舉成員(具體描述在 Enumerations)默認(rèn)也是可哈希的(hashable)。

創(chuàng)建一個(gè)空字典

和字典一樣,你可以使用確定類(lèi)型的語(yǔ)法創(chuàng)建一個(gè)空的字典。

var namesOfIntegers = [Int:String]()
// namesOfIntegers 是一個(gè)空的 [Int: String] 類(lèi)型的字典

這個(gè)例子創(chuàng)建一個(gè)Int,String類(lèi)型的字典來(lái)儲(chǔ)存可讀性較好的整數(shù)值。它的鍵是Int類(lèi)型,它的值是String類(lèi)型。

如果 上下文(context )中已經(jīng)提供類(lèi)型信息,可用一個(gè)字典實(shí)量(Dictionary Literal)創(chuàng)建一個(gè)空的字典,寫(xiě)作[;](由一對(duì)[]包含一個(gè)冒號(hào):)

namesOfIntegers[16] = "sixteen"
// namesOfIntegers現(xiàn)在包含1 個(gè)鍵值對(duì)
namesOfIntegers = [:]
// namesOfIntegers 是一個(gè)類(lèi)型為Int, String的空字典。

字典實(shí)量(Dictionary Literals)

你可以直接用一個(gè)字典實(shí)量(Dictionary Literals)初始化一個(gè)字典。和前面定義一個(gè)數(shù)組實(shí)量(Array Literals)的語(yǔ)法一樣。字典實(shí)量(Dictionary Literals)就是使用簡(jiǎn)略寫(xiě)法直接寫(xiě)一個(gè)或者多個(gè)對(duì)應(yīng)的鍵和值對(duì)來(lái)定義一個(gè)字典。

一個(gè)鍵值對(duì)是一個(gè)鍵和值的組合。在字典實(shí)量(Dictionary Literals)里面,每一個(gè)鍵值對(duì)總是用一個(gè)冒號(hào)把鍵和值分割。鍵值對(duì)的寫(xiě)法就想是一個(gè)列表,使用逗號(hào)分割,并被一對(duì)中括號(hào)[]包含著:

[key 1: value 1, key 2: value 2, key 3: value 3]

在下面的例子,將會(huì)創(chuàng)建一個(gè)字典來(lái)儲(chǔ)存國(guó)際機(jī)場(chǎng)的名字。在這個(gè)字典里面,鍵是三個(gè)字的國(guó)際航空運(yùn)送協(xié)會(huì)代碼,以及它的值是機(jī)場(chǎng)的名稱(chēng):

var airport :[String: String] = ["TYO": "Tokyo", "DUB": “Dublin"]

airport字典被定義為一個(gè)類(lèi)型為[String:String],這意味這,這個(gè)字典的鍵類(lèi)型是字符串String,和它的值的類(lèi)型也是String。

注意
airport字典是被定義為一個(gè)變量(使用var 標(biāo)識(shí)符)而不是常量(使用let 標(biāo)識(shí)符),所以在下面的例子可以直接添加元素。

airport字典使用一個(gè)包含兩個(gè)鍵值對(duì)的字典實(shí)量(Dictionary Literals)來(lái)初始化。第一對(duì)有一個(gè)叫“TYO”的鍵和一個(gè)叫“Tokyo”的值,第二對(duì)有一個(gè)叫“DUB”的鍵和一個(gè)叫“Dublin”的值。

這個(gè)字典實(shí)量(Dictionary Literals)包含兩個(gè)字符串(String):字符串對(duì)。這符合airport變量定義的類(lèi)型(一個(gè)字典只包括字符串(String)鍵和字符串(String)值),所以在分配字典實(shí)量(Dictionary Literals)的時(shí)候被允許作為airport字典的兩個(gè)初始化元素。

和數(shù)組一樣,如果你初始化一個(gè)字典的時(shí)候使用相同的類(lèi)型,你可以不指明字典的類(lèi)型。
airport初始化可以用下面這個(gè)簡(jiǎn)略寫(xiě)法來(lái)代替:

var airports = ["TYO": "Tokyo", "DUB": “Dublin”]

因?yàn)樗械逆I在字面上都是相同的類(lèi)型,同樣,所有的值也是同樣的類(lèi)型,所以Swift可以推斷為[String:String]是airports字典的正確類(lèi)型。

讀取和修改字典

你可以通過(guò)屬性,方法或者下標(biāo)來(lái)讀取和修改字典。和數(shù)組一樣,你使用只讀的count屬性來(lái)檢查字典(Dictionary)包含多少個(gè)元素。

 print("The dictionary of airports contains \(airports.count) items.")
// 打印 "The dictionary of airports contains 2 items."

你可以使用下標(biāo)語(yǔ)法給一個(gè)字典添加一個(gè)元素。使用合適類(lèi)型作為新的鍵,并分配給它一個(gè)合適類(lèi)型的值

 airports["LHR"] = "London"
//  airports dictionary 現(xiàn)在有 3 items

你也可以使用下標(biāo)語(yǔ)法去改變一個(gè)特定鍵所關(guān)聯(lián)的值。

airports["LHR"] = "London Heathrow"
//"LHR" 的值已經(jīng)被改變?yōu)?"London Heathrow"

同樣, 使用字典的updateValue(forKey:) 方法去設(shè)置或者更新一個(gè)特定鍵的值 . 和上面的下標(biāo)例子一樣, updateValue(forKey:) 方法如果鍵不存在則會(huì)設(shè)置它的值,如果鍵存在則會(huì)更新它的值, 和下標(biāo)不一樣是, updateValue(forKey:) 方法如果更新時(shí),會(huì)返回原來(lái)舊的值,意味著你可以使用這個(gè)來(lái)判斷數(shù)據(jù)是否發(fā)生了更新。

updateValue(forKey:) 方法返回一個(gè)和字典的值相同類(lèi)型的可選值. 例如,如果字典的值的類(lèi)型時(shí)String,則會(huì)返回String? 或者叫“可選String“,這個(gè)可選值包含一個(gè)如果值發(fā)生更新的舊值和如果值不存在的nil值。

if let oldValue = airports.updateValue("Dublin International", forKey: "DUB") {
    print("The old value for DUB was \(oldValue).")
}
// prints "The old value for DUB was Dublin."

你也可以使用下標(biāo)語(yǔ)法通過(guò)特定的鍵去讀取一個(gè)值。因?yàn)槿绻闹挡淮嬖诘臅r(shí)候,字典的下標(biāo)語(yǔ)法會(huì)返回一個(gè)字典的值的類(lèi)型的可選值。如果字典中的鍵包含對(duì)應(yīng)的值,這字典下標(biāo)語(yǔ)法會(huì)返回這個(gè)鍵所對(duì)應(yīng)的值,否則返回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 International."

你可以使用下標(biāo)語(yǔ)法把他的值分配為nil,來(lái)移除這個(gè)鍵值對(duì)。

airports["APL"] = "Apple International"
// "Apple International" 不是APL的真實(shí)機(jī)場(chǎng),所以刪除它
airports["APL"] = nil
// APL已經(jīng)從字典中被移除

同樣,從一個(gè)字典中移除一個(gè)鍵值對(duì)可以使用removeValueForKey方法,這個(gè)方法如果存在鍵所對(duì)應(yīng)的值,則移除一個(gè)鍵值對(duì),并返回被移除的值,否則返回nil。

if let removedValue = airports.removeValueForKey("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 International."

遍歷字典

你可以使用一個(gè)for-in循環(huán)來(lái)遍歷字典的鍵值對(duì)。字典中的每一個(gè)元素都會(huì)返回一個(gè)元祖(tuple),你可以在循環(huán)部分分解這個(gè)元祖,并用臨時(shí)變量或者常量來(lái)儲(chǔ)存它。

for (airportCode, airportName) in airports {
    print("\(airportCode): \(airportName)")
}
// TYO: Tokyo
// LHR: London Heathrow

更多有關(guān)for-in 循環(huán)的信息, 參見(jiàn) For Loops.

你也可以讀取字典的keys屬性或者values屬性來(lái)遍歷這個(gè)字典的鍵或值的集合。

for airportCode in airports.keys {
    print("Airport code: \(airportCode)")
}
// Airport code: TYO
// Airport code: LHR
for airportName in airports.values {
    print("Airport name: \(airportName)")
}
// Airport name: Tokyo
// Airport name: London Heathrow

如果你需要一個(gè)接口來(lái)創(chuàng)建一個(gè)字典的鍵或者值的數(shù)組實(shí)例,你可以使用keys或者values屬性來(lái)初始化一個(gè)數(shù)組。

let airportCodes = Array(airports.keys)
// airportCodes is ["TYO", "LHR"]
let airportNames = Array(airports.values)
// airportNames is ["Tokyo", "London Heathrow"]

注意
Swift中的字典類(lèi)型是非序列化集合,序列化取回鍵,值,或者鍵值對(duì)的順序是不明確的。

可變集合類(lèi)型

數(shù)組和字典都是在一個(gè)集合中一起儲(chǔ)存多個(gè)變量.如果你創(chuàng)建一個(gè)數(shù)組或者字典,再包含一個(gè)變量,創(chuàng)建的這個(gè)變量被稱(chēng)為可變的(mutable) 這意味這,你可以在創(chuàng)建之后增加更多的元素來(lái)改變這個(gè)集合的長(zhǎng)度,或者移除已經(jīng)包含的。相反的, 如果你把一個(gè)數(shù)組或者字典定義為常量,則這個(gè)數(shù)組或者字典不是可變的,他們包含的項(xiàng)數(shù)并不能被改變。

在字典中,不可變也意味著你不能替換已經(jīng)存在的鍵的值。一個(gè)不可變字典,一旦被設(shè)置就不能改變。

數(shù)組的不可變有一點(diǎn)點(diǎn)的不同。然而,你仍然不能做任何改變項(xiàng)數(shù)的操作。但是你可以重新設(shè)置一個(gè)已經(jīng)存在的索引,這使得當(dāng)Swift的數(shù)組的長(zhǎng)度確定時(shí),能更好地優(yōu)化數(shù)組的性能。

擁有可變行為的數(shù)組也影響著數(shù)組實(shí)例的分配和修改,更多內(nèi)容參見(jiàn)Assignment and Copy Behavior for Collection Types.

注意
在一個(gè)集合的項(xiàng)數(shù)不需要被改變時(shí),創(chuàng)建不可變集合是非常好的嘗試。這樣的話(huà)Swift編譯器就能充分利用你所創(chuàng)造的集合的性能。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容