Swift 程式語言 — 集合類型(2) — Set & Dictionary

讓我們來看看剩下的兩種無序的集合類型,Set 以及 Dictionary 吧!

Jeremy Xue
Jeremy Xue ‘s Blog
12 min readDec 5, 2018

--

前言:

前面我們介紹到了集合類型中的 Array ,這次教學我們要來繼續講解剩下的兩種無序的集合類型 SetDictionary

⎮ Set

Set 在集合中儲存相同類型的不同值,並且沒有定義其順序。當你需要確認項目只出現一次或是項目中的順序是不重要時,你可以使用 Set 而不是 Array

● Set 類型中的 HashValue

類型必須是能 hashable 才能儲存在 Set 中,也就是類型必須提供計算自身的 hashValue 的方法。HashValue 是一個 Int 類型的值,對於同等比較所有物件都是相同的。也就是下列這段程式碼的意思:

默認情況下,所有 Swift 的基礎類型都是能 hashable 的(StringIntDoubleBool),並且可以用於設置 Set 的值類型或是 Dictionarykey 類型。Enumeration 中沒有關聯值的 case 也是能 hashable 的。

你可以使用你自定義的類型透過遵循 Swift 基本庫的 Hashable 協議來作為 Set 值類型或是 Dictionary 的 key 類型。遵循 Hashable 的類型必須提供名為 hashValue 的 Int 屬性。類型中的 hashValue 返回值不需要在同一個程序中的不同執行階段或不同程序中相同。

因為 Hashable 協議遵循符合 Equatable,所以遵循的類型還必須提供等於運算符(==)的實現,Equatable 協議要求任何遵循的實現都必須是等價的關係。也就是說,對於所有值 a, b, c 想等的實現必須滿足下列三個條件。

● Set 類型語法:

你可以透過下列方式宣告一個空的 Set,它不像 Array 有簡寫的方式。

● 創建一個空的 Set:

Array 和 Set 在很多地方其實很雷同,包含其方法、操作等等。但是還是要了解其差別,並不是所有地方都相同。

我們一樣可以透過上列方式來創建一個空的 Set,我們一樣可以透過 isEmpty 來確認是否為空的 Set,以及使用 count 來查看集合數量:

我們一樣可以直接賦予他一個 [] 使它變成一個空的 Set

● 創建一個有預設值的 Set:

我們也可以透過給他預設值的情況,設置一個 Set,我們可以使用以下方式來創建他:

● Set 的插入、刪除以及是否包含 :

這邊我們跟 Array 一樣能夠執行與插入,差異點是在於因為 Set 是無序排列,所以我們不需要也無法告訴它插入和刪除位置(index):

在 Set 中加入一個 “Test” 元素

刪除也是如此,我們只需要告訴該元素名稱即可:

移除 Set 中的特定元素

接著我們可能需要知道 Set 中是否包含著某個元素,我們可以使用 contains(member:) 來檢查:

如果為 true 表示 Set 中有包含此元素,反之則無

● 遍歷 Set:

這邊我們一樣可以使用 for-in 迴圈來遍歷 Set

因為是無序排列,所以每次順序都不同

當你想要 Set 裡面能夠有序排列時,我們可以透過 sorted() 方法,讓 Set 跟據預設或是自定義的規則來執行排序,讓該 Set 變成有序排列。也因為它變成有序排列,所以 Set.sorted() 也就等同於 Array

● 執行 Set 操作:

你可以有效地去執行基本的 Set 操作,例如:結合兩個 Set,判斷兩個 Set 有哪些值,或者確定兩個 Set 是否包含全部、一些或是不包含的值。

  • 使用 intersection(_:)方法來創建一個只包含兩個 Set 共有值的 Set
  • 使用 symmetricDifference(_:)方法來創建一個只包含兩個 Set 各自有的且沒有共有值的 Set
  • 使用 union(_:)方法來創建一個包含兩個 Set 所有值的 Set
  • 使用 subtracting(_:)方法來創建一個兩個 Set 當中不包含某個 SetSet

這邊借官方的範例來使用,這裡我們有三種不同的 Set:

然後配合上面四種方法操作後的結果如下,最後使用 sorted() 排列:

● Set 成員關係以及相等性:

下圖描繪了三個 Set(a, b, c),其中重疊區域表示之間共享的元素。Set a Set bsuperset,因為 a 包含 b 中的所有元素。相反的 Set bSet a 的子集,因為 b 中所有的元素也包含在 a 中。Set bSet c 彼此不相交,因為他們沒有共同的元素。

  • 使用 “相等” 運算符 (==)來判斷兩個 Set 是否包含相同的值
  • 使用 isSubset (of:) 方法來確定一個 Set 的所有值是被某 Set 包含,是否為其 subset
  • 使用 isSuperset(of:) 方法來確定一個 Set 是否包含某個 Set 的所有值,是否為其 superset
  • 使用 isStrictSubset(of:) 或者 isStrictSuperset(of:)方法來確定是個 Set 是否為某一個 Setsubset或者superset,但並不相等;
  • 使用 isDisjoint(with:)方法來判斷兩個 Set 是否擁有完全不同的值。

這邊我們有三種不同動物的 Set ,讓我們測試一下上述這幾種方法吧,可以使用 Playground 或是 Command Line 來練習:

⎮ Dictionary

Dictionary 儲存類型相同的值與類型相同的 key 之間的關聯,沒有定義的排序。每個值都與唯一的 key 關聯,這個 keyDictionary 中做為這個值的識別符(identifier)。不同於 Array 中的項目,Dictionary 的項目沒有特定的順序,為無序集合類型。當你需要識別符查找某個項目時,可以使用 Dictionary

● 創建空的 Dictionary:

這邊可以看到我們兩個 Dictionarykey 的類型為 Int,其值類型為 String 。你可以透過一個 [:] 賦予 Dictionary 一個空的 Dictionary 值。

先在 Dictionary 中新增一個項目後賦予一個 [:] 作為空的 Dictionary

● 用字典字面量 (Dictionary Literal)創建 Dictionary

我們可以提供 Dictionary Literal 作為 Dictionary 的預設值,來創建我們的 Dictionary ,每個項目的組合為 key:value ,每個項目須以 , 來作為間隔:

我們在提供預設值後,也能夠省略常數或變數的後的類型標註,該 Dictionary 類型會根據其 key:value 個別的類型推斷出來:

● 訪問以及修改 Dictionary

我們一樣可以使用 count 屬性來查看 Dictionary 中的項目數:

還有使用 isEmpty 屬性來查看是否為空的 Dictionary

你可以透過其該項目的 key 值來訪問項目值,但是你會發現它會是個 Optional 類型的值:

這是因為 Dictionary 無法確定你所給它的這個 key 值是否能夠找到對應的值,若是它無法找到對應的值,就會返回一個 nil

所以當我今天想要修改某個項目的值我可以透過其 key 來找出對應的值,如果找不到這個 key 的話,則會在 Dictionary 中加入這組 key-value 的項目:

在第 2 行修改 myDictionary[1] 的內容,在第 3 行新增一個 key = 5, value = “Swift ” 的項目

我們也能使用 Dictionary 中的 updateValue (value:,key:) 的方式來更新 key 所對應的值。如同上面的操作相同,如果找到對應 key 的值,就進行值的更新,反之則會新增:

我們可以使用 myDictionary.removeValue(forKey:) 來刪除 Dictionarykey 所對應的值,也能夠過賦予 key 的對應值一個 nil 來清除項目:

我們也能透過 Optional Binding 來判斷是否 Dictionary 中有沒有 key 所對應的值:

在我們透過 updateValue(value:forKey:) 或是 removeValue(forKey:) 修改 Dictionary 時,同時也會返回給我們修改的項目,若沒有被修改則會返回給我們 nil,所以這邊也能使用 Optional Binding 來判斷是否有被修改:

查看是否有項目被更新
查看是否有項目被移除

● 遍歷 Dictionary

當然我們也能使用 for-in 迴圈來查看 Dictionary 中的所有項目,並且查看其項目的 keyvalue

我們也可以透過一個 Tuple 作為複合值來個別印出:

當然我們也能夠選擇只去 for-in 循環 Dictionary 中的 key 或是 value

如果你需要使用帶有 Array 實例的 API 的 Dictionarykeysvalues,那麼我們可以使用 Dictionarykeys 或是 values 來初始化一個新的 Array

將 Dictionary 中的 keys 和 values 賦給一個 Array

後記:

那麼我們集合類型的教學就到這邊告一段落了,希望大家在之後使用這三種集合類型的時候,能夠根據你的需求來選擇適合的集合類型,然後也能夠活用這三種集合類型的方法,能夠新增、刪除修改類型內的資料。如果你能夠講出三種集合類型的相似點以及不同點,那麼你就對於這三者的特性有一定的理解了。

--

--

Jeremy Xue
Jeremy Xue ‘s Blog

Hi, I’m Jeremy. [好想工作室 — iOS Developer]