集合類型 (Collection Types)
自從蘋果2014年發布Swift,到現在已經兩年多了,而Swift也來到了3.1版本。去年利用工作之余,共花了兩個多月的時間把官方的Swift編程指南看完。現在整理一下筆記,回顧一下以前的知識。有需要的同學可以去看官方文檔>>。
Swift提供了三種集合類型:數組(Array
)、集合(Set
)、字典(Dictionary
)。Array
是有順序的值的集合;Set
是多個唯一的值的無序集合;Dictionary
是無序的鍵值對集合。
注意:Swift的Array
、Set
和Dictionary
都屬于泛型集合。
數組 (Array)
數組只能存儲相同類型的值。相同的值可以出現在數組的不同位置中。
數組類型的速記語法 (Array Type Shorthand Syntax)
一個數組的類型是這樣寫的:Array<Element>
,Element
是數組元素值的類型,也可以簡寫成:[Element]
。
創建一個空數組 (Creating an Empty Array)
var someInt = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// Prints "someInts is of type [Int] with 0 items."
someInt
被推斷為[Int]
類型。
如果上下文已經提供了數組的類型,空素組還可以寫成[]
:
someInt.append(3)
// someInts now contains 1 value of type Int
someInt = []
// someInts is now an empty array, but is still of type [Int]
創建一個有默認值的數組 (Creating an Array with a Default Value)
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)
let 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)
var shoppingLis = ["Eggs", "Milk"]
// shoppingList has been initialized with two initial items
訪問和修改數組 (Accessing and Modifying an Array)
獲取數組的個數:
print("The shopping list contains \(shoppingList.count) items.")
// Prints "The shopping list contains 2 items."
判斷數組元素的個數是否為0:
if shoppingList.isEmpty {
print("The shopping list is empty.")
} else {
print("The shopping list is not empty.")
}
追加一個元素:
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"
更改元素:
shoppingList[0] = "Six eggs"
// the first item in the list is now equal to "Six eggs" rather than "Eggs"
使用下標一次性更改多個元素,甚至要更改的元素個數可以不等于新數組的個數:
shoppintList[4...6] = ["Bananas", "Apples"]
// 用兩個替換三個
在特定的位置插入元素:
shoppingList.insert("Maple syrup", at: 0)
// shoppingList now contains 7 items
// "Maple Syrup" is now the first item in the list
刪除特定位置的元素,并且返回被刪除的元素:
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
刪除最后一個元素:
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
遍歷整個數組 (Iterating Over an Array)
使用for-in
遍歷:
for item in shoppingList {
print(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas
使用enumerated()
方法遍歷,這個方法返回包含索引和索引對應的元素的多元組:
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
集合 (Sets)
集合中無順序地存儲了同一類型的值,并且里面的每一個值都是唯一的。在元素的順序不重要或者要求每一個元素都需要唯一的時候,可以使用集合,而不用數組。
集合類型的哈希值 (Hash Values for Set Types)
集合里面的元素類型必須hashable,也就是說,這個元素類型必須提供一個方法來計算他自己的哈希值。一個哈希值是一個用來判斷兩個對象是否相等的Int
類型的整數。例如,如果a == b
,那么a.hashValue == b.hashValue
。
所有Swift的基本類型(例如String
、Int
、Double
、Bool
)默認都是hashable的,都可以作為集合的值類型或者字典的鍵類型。沒有關聯值的枚舉值默認也是hashable的。
我們可以自定義類型,并且遵循Hashable
協議,作為集合或者字典鍵的值類型。自定義的類型必須提供一個能讀取的Int
類型的屬性,并命名為hashValue
。在不同的程序或者同一個程序運行多次中,不要求每次hashValue
屬性返回的值都相等。
因為Hashable
協議遵循Equatable
協議,所以我們自定義的類型還需要提供一個相等運算符(==
)的實現。Equatable
協議要求每一個==
的實現是一個等價關系。也就是說,==
的實現必須滿足下面三個條件:
-
a == a
(自反性) -
a == b
,說明b == a
(對稱性) -
a == b && b == c
,說明a == c
(傳遞性)
集合類型語法 (Set Type Syntax)
使用Set<Element>
來設置集合類型,Element
是集合存儲的元素類型。
創建和初始化一個空集合 (Creating and Initializing an Empty 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
被推斷為Set<Character>
類型。
同樣地,如果上下文提供了集合的類型信息,可以使用[]
來創建一個空的集合:
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)
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres has been initialized with three initial items
集合的類型不能通過數組的字面值來推斷,所以Set
的類型必須明確聲明。但是因為Swift的類型推斷,如果用一個包含相同類型字面值的數組來初始化集合,我們可以不寫集合的類型。例如:
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
因為數組的全部字面值都是同一類型,所以Swfit能推斷出Set<String>
是favoriteGenres
的正確類型。
訪問和修改集合 (Accessing and Modifying a Set)
使用count
屬性獲取集合元素個數:
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."
判斷是否包含某個元素:
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."
遍歷整個集合 (Iterating Over a Set)
for genre in favoriteGenres {
print("\(genre)")
}
// Jazz
// Hip hop
// Classical
Swift的集合類型沒有定義順序,我們可以使用sorted()
方法來排序,這個方法使用<
運算符將元素從小到大排列:
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
// Classical
// Hip hop
// Jazz
執行集合操作 (Performing Set Operations)
基本集合操作 (Fundamental Set Operations)
下圖是集合a
和b
執行了不同的方法之后,得出的結果圖:
- 使用
intersection(_:)
方法得到兩個集合共有的元素,并用這些相同的元素創建一個新的集合 - 使用
symmetricDifference(_:)
方法得到除了兩個集合共有的元素外的所有元素,并用這些相同的元素創建一個新的集合 - 使用
union(_:)
方法得到兩個集合的所有元素,并用這些相同的元素創建一個新的集合 - 使用
subtracting(_:)
方法減去與指定集合相同的元素后剩下的元素,并用剩下的元素創建一個新的集合
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)
下圖演示了三個集合:a
、b
和c
,重疊區域代表有相同的元素。集合a
是集合b
的父集合,因為a
包含了b
的所有元素;相反,b
是a
的子集合。集合b
和集合c
互不相交,因為他們沒有相同的元素。
- 使用“是否相等”運算符 (
==
)來判斷兩個集合的所有元素是否相等 - 使用
isSubset(of:)
方法判斷集合的所有元素是否包含于指定集合 - 使用
isSuperset(of:)
方法判斷集合是否包含指定集合的所有元素 - 使用
isStrictSubset(of:)
或者isStrictSuperset(of:)
方法判斷集合是否子集合或者父集合,但是不等于指定的集合 - 使用
isDisjoint(with:)
方法判斷兩個集合是否有相同的元素
let houseAnimals: Set = ["??", "??"]
let farmAnimals: Set = ["??", "??", "??", "??", "??"]
let cityAnimals: Set = ["??", "??"]
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true
Dictionaries (字典)
字典是一個無序集合中相同類型的鍵和相同類型的值的關聯。每一個值關聯著一個唯一的鍵。
字典類型速記語法 (Dictionary Type Shorthand Syntax)
使用Dictionary<Key, Value>
來指定字典的類型。
注意:字典的Key
類型必須遵循Hashable
協議,就像集合的值一樣。
還可以是用簡短的形式[Key: Value]
來指定字典的類型.
創建一個空字典 (Creating an Empty Dictionary)
var namesOfIntegers = [Int: String]()
// namesOfIntegers is an empty [Int: String] dictionary
如果上下文已經提供了類型信息,可以使用[:]
來創建一個空字典:
namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]
利用字典字面值來創建字典 (Creating a Dictionary with a Dictionary Literal)
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
訪問和修改字典 (Accessing and Modifying Dictionary)
獲取字典鍵值對的個數:
print("The airports dictionary contains \(airports.count) items.")
// Prints "The airports dictionary contains 2 items."
判斷字典中鍵值對的個數是否為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 Heathrow"
// the value for "LHR" has been changed to "London Heathrow"
還可以使用updateValue(_:forKey:)
方法來設置或更新一個鍵對應的值,并返回一個可選類型的值。如果這個鍵不存在,那么就添加一個新的鍵值對,并返回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."
使用下標語法來獲取鍵對應的值:
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."
遍歷整個字典 (Iterating Over a Dictionary)
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
// YYZ: Toronto Pearson
// LHR: London Heathrow
使用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
如果要使用字典的所有鍵和所有值,可以利用數組的API來創建:
let airportCodes = [String](airports.keys)
// airportCodes is ["YYZ", "LHR"]
let airportNames = [String](airports.values)
// airportNames is ["Toronto Pearson", "London Heathrow"]
Swift的字典類型沒有定義順序,為了遍歷經過排序的所有鍵和所有值,需要使用keys
和values
屬性的sorted()
方法。
第四部分完。下個部分:【Swift 3.1】05 - 控制流 (Control Flow)
如果有錯誤的地方,歡迎指正!謝謝!