Swift 5.1 (4) - 集合類型

級別: ★☆☆☆☆
標簽:「iOS」「Swift 5.1」「Set」「Array」「Dictionary」
作者: 沐靈洛
審校: QiShare團隊


集合類型

Swift提供三種主要的集合類型,稱為ArraySetDictionary,用于存儲值的集合。Array是有序的值的集合。Set是唯一值的無序集合。Dictionary是鍵值關聯的無序集合。
可變集合:
如果創建數組,集合或字典,并將其分配給變量,則創建的集合將是可變的。我們可以通過添加,刪除或更改集合中的項目來更改集合。如果將數組,集合或字典分配給常量,則該集合是不可變的,并且其大小和內容不能更改。
數組:
數組可以存儲相同類型的值,并且相同的值可以在數組不同位置多次出現。

  1. 數組類型的簡寫語法:a. Array <Element> b. [Element]其中Element是允許數組存儲的值的類型。其中[Element]簡寫形式優選。
  2. 創建一個空的數組:
    使用初始化語法創建某個類型的空數組:
//方式一
let intArray = Array<Int>()
print("intArray中有\(intArray.count)個元素")
//方式二
let intArray = [Int]()
print("intArray中有\(intArray.count)個元素")

如果上下文已經提供了數組中的類型信息,則數組存儲的值得類型就是確定的。

  1. 創建帶有初始值得數組:
    Swift的Array類型提供了一個初始化方法,用于創建一個特定大小的數組,并將其所有值設置為相同的默認值。
let defaultValueArray = Array.init(repeating: "你好", count: 3)
print(defaultValueArray)//!< ["你好", "你好", "你好"]
  1. 兩個數組相加:
    使用加法運算符+將兩個具有兼容類型的現有數組相加來創建新數組。新數組的類型是從我們添加的兩個數組的類型推斷出來的。這兩個相加的數組的類型必須要可以兼容,否則編譯器會報錯。
let defaultValueArray = Array.init(repeating: "你好", count: 3)
let secondValueArray = Array.init(repeating: "大佬", count: 2)
let thirdValueArray = defaultValueArray + secondValueArray
print(thirdValueArray)//!< ["你好", "你好", "你好", "大佬", "大佬"]
  1. 使用字面量元素初始化數組:
    使用數組字面量元素初始化數組,語法:[value 1, value 2, value 3]
let literalArray = ["逗哥","刀哥"] //!< ["逗哥", "刀哥"] 有初值,可以類型推斷,不必聲明數組的類型
let literalArray1 : [Int] = [6,7]//!< [6, 7] 聲明了類型
  1. 數組的訪問和修改:
    count屬性:訪問數組元素的個數。isEmpty屬性值Bool類型數組判空,相較Array.count == 0更高效。
if intArray.isEmpty {
   print("intArray:\(intArray)中有\(intArray.count)個元素")//!< intArray:[]中有0個元素
}

使用append(_:)方法拼接新項到數組的末尾

var appendArray = ["飛哥","強哥"]
appendArray.append("大哥")//!< ["飛哥", "強哥", "大哥"]

使用加法賦值運算符+=追加一個或多個兼容項的數組:

var appendArray = ["飛哥","強哥"]
let array1 = ["finally","ok"]
let array2 = ["拯救","靜","\u{65}"]
appendArray += array1 //!< ["飛哥", "強哥", "finally", "ok"]
appendArray += array2 //!< ["飛哥", "強哥", "finally", "ok", "拯救", "靜", "e"]

使用下標從數組中取值:

let literalArray = ["逗哥","刀哥"] //!< ["逗哥", "刀哥"]
let firstStr = literalArray[0]
print(firstStr) //!< 逗哥

使用下標更改給定索引處的值:

var literalArray = ["逗哥","刀哥"] //!< ["逗哥", "刀哥"]
literalArray[0] = "加油"
print(literalArray) //!< ["加油", "刀哥"]

使用范圍下標一次性更改值,即使替換值的數組長度與要替換的范圍不同。但是必須不能越界:下標范圍必須在當前數組的有效范圍內。

var totalArray = ["飛哥", "強哥", "finally", "ok", "拯救", "靜", "e"]
totalArray[...3] = ["","","","?"]//!< ["", "", "", "?", "拯救", "靜", "e"]
totalArray[5..<7] = ["融合了"]//!< 5..<7有兩個元素 被替換成了一個 log:["", "", "", "?", "拯救", "融合了"]
print(totalArray)

使用insert(_:at :)方法在指定索引處將指定項插入數組:

var literalArray = ["逗哥","刀哥"] //!< ["逗哥", "刀哥"]
literalArray.insert("妄言", at: 1)//!< ["逗哥", "妄言", "刀哥"]
print(literalArray)

使用remove(at :)方法從數組中刪除指定項并返回刪除項

var literalArray = ["逗哥","刀哥"] //!< ["逗哥", "刀哥"]
literalArray.insert("妄言", at: 1)//!< ["逗哥", "妄言", "刀哥"]
let deleteStr = literalArray.remove(at: 0)//!< ["妄言", "刀哥"]
print(literalArray,"刪除了:\(deleteStr)")//!< ["妄言", "刀哥"] 刪除了:逗哥

使用removeLast()從數組中刪除最終項并返回刪除項。以避免需要查詢數組的count屬性.

var literalArray = ["逗哥","刀哥"] //!< ["逗哥", "刀哥"]
literalArray.removeLast()
//!< 也可以removeFirst()
literalArray.removeFirst()
  1. 數組的遍歷
    使用for-in循環遍歷
var literalArray = ["逗哥","刀哥"] //!< ["逗哥", "刀哥"]
for item in literalArray {
    print(item,"", separator: " ", terminator: "")//!< 逗哥 刀哥
}

使用enumerated()方法迭代數組:同時遍歷各項的整數索引及其值。
返回由整數和各項的值組成的元組。

for item in literalArray.enumerated() {
    print(item.1) //!< 逗哥 刀哥
    print(item.0) //!< 0 1
    print(item) //!< (offset: 0, element: "逗哥") (offset: 1, element: "刀哥")
}

集合:
Set是唯一值的無序集合,這個特性可以讓我們在適當的場景下去使用。

  1. 集合類型的值(散列,哈希)
    必須是可散列的類型才能存儲在集合中。 即:集合中存儲的類型必須提供能夠計算自身散列值的方法。哈希值是一個Int值,對于所有相互比較相等的對象都是相同的,例如a == b,則遵循a.hashValue == b.hashValue
    默認情況下,Swift的所有基本類型,如StringIntDoubleBool都是可哈希的,并且可以用作集合中的值類型或字典的key類型。默認情況下,沒有關聯值的枚舉類型也是可以哈希的。
    注意點:我們可以使用自定義符合Hashable協議的類型作為集合中的值類型或字典的key類型。符合Hashable協議的類型必須提供名為hashValueInt類型的可訪問的屬性。該自定義類型的hashValue屬性在同一程序的不同執行或不同程序中執行時返回的值不需要相同。因為Hashable協議繼承Equatable協議,所以符合Hashable協議的類型還必須提供運算符==的實現。
    Equatable協議要求任何符合==實現的,都是相等關系。==的實現必須要滿足三個條件:反身性,對稱性,及物性。
    比如實現Equatable協議的類型的值a,b,c:
    ?反身性表示:a == a
    ?對稱性表示:a == b則b == a
    ?及物性表示:a == b && b == c則 a == c
  2. 集合類型語法:Set <Element>,其中Element是允許集合存儲的類型。與數組不同,集合沒有等效的簡寫形式。
  3. 創建空集合:
let emptySet = Set<Int>()
let emptyCharacterSet = Set<Character>()

如果上下文已經提供了集合中的類型信息,則集合中存儲的值得類型就是確定的。

  1. 使用數組創建集合
    使用數組初始化集合,將一個或多個值寫入集合中。
var favoriteGenres :Set<String> = ["可是","怎么","能夠","如此"]
//! 由于Swift的類型推斷的存在,在上下文提供了類型信息后,可以簡寫為
var favoriteGenres :Set = ["可是","怎么","能夠","如此"]
  1. 集合的訪問和修改
    count屬性:訪問集合中元素的個數。isEmptyBool類型的屬性值用于集合判空。
if favoriteGenres.isEmpty {
    print("favoriteGenres集合中沒有元素")
    
} else {
    print("favoriteGenres集合有 \(favoriteGenres.count)個元素")
    
}

使用insert(_:)方法添加一個新項到集合中:

favoriteGenres.insert("聰明")//!< ["聰明", "能夠", "可是", "怎么", "如此"]

使用remove(_ :)方法從集合中刪除指定項并返回刪除項:如果該項目是該集合的成員,則刪除該項目,并返回已刪除的值,如果該集合不包含該項目,則返回nil

if let removeItem = favoriteGenres.remove("聰明") {
    print("\(removeItem)此項已被移除")
} else {
    print("favoriteGenres集合中沒有該項")
}

使用contains(_:)方法,判斷集合中是否包含某一項。

if favoriteGenres.contains("好的") {
    print("包含")
} else {
    print("不包含")
}
  1. 集合的遍歷
    使用for-in循環遍歷
var favoriteGenres :Set = ["可是","怎么","能夠","如此"]
for item in favoriteGenres {
    print(item,"",separator: " ", terminator: "")//!< 能夠 怎么 如此 可是
}

使用sorted()方法,以特定順序遍歷集合的值,該方法將集合的元素使用<運算符排序后的元素作為數組返回。

for item in favoriteGenres.sorted() {
    print(item)
}
  1. 集合的操作
    兩組集合a和b以陰影區域表示的各種集合操作的結果。


    集合操作圖示
  • 使用intersection(_ :)方法創建一個只包含兩個集合共有的值的新集合。
  • 使用symmetricDifference(_ :)方法創建一個新集合,其中包含任一集合中的值,但不包含兩個集合共同的部分。
  • 使用union(_ :)方法創建一個包含兩個集合中所有值的新集合。
  • 使用subtracting(_:)方法創建一個值不在指定集中的新集。
let set1 : Set<Int> = Set.init(arrayLiteral: 1,5,7,2)
let set2 : Set<Int> = [2,4,6,8]
let set3 = set1.intersection(set2)//!< 預期:[2] 實際 [2]
//除了相同以外的其他元素
let set4 = set1.symmetricDifference(set2)//!< 預期:[1,5,7,4,6,8] 實際: [6, 4, 5, 7, 8, 1]
let set5 = set1.union(set2)//!< 預期[6, 4, 5, 7, 8, 1,2] 實際 [4, 5, 2, 8, 1, 7, 6]
//從set1中去除與set2有關的所有元素
let set6 = set1.subtracting(set2)//!< 預期[1,5,7] 實際[1, 7, 5]
  1. 集合之間的關系與相等判斷:三個集合a,b和c,集合a包含集合b中的所有元素,則稱集合a是集合b的超集,相反,集合b是集合a的子集。集合b和集合c沒有共同的元素。集合a和集合c有共同的元素,則集合a和集合c相交。
    ?使用運算符==確定兩個集合是否包含所有相同的值。
    ?使用isSubset(of :)方法確定集合的所有值是否包含在指定集合中。
    ?使用isSuperset(of :)方法確定集合是否包含指定集合中的所有值。
    ?使用isStrictSubset(of :)或isStrictSuperset(of :)方法來確定集合是否是指定集合的??子集或超集,但不能判斷相等。
    ?使用isDisjoint(with :)方法確定兩個集合是否沒有有共同的值。
let set : Set<Int> = [1,5,2,7]
let set1 : Set<Int> = Set.init(arrayLiteral: 1,5,7,2,8)
//! 判斷相等
if set == set1 {
    print("相等")
} else {
    print("不相等")
}
//!判斷子集與超集
if set.isStrictSubset(of: set1){//!< set是否是set1的子集
    print("set是set1的子集")
}
if set1.isStrictSubset(of: set){//!< set1是否是set的超集
    print("set1是set的超集")
}
//!< 判斷是否不相交
if set1.isDisjoint(with: set) {//!< `true`元素不相交 否則`false`
    print("set1和set不相交")
} else {
    print("set1和set相交")
}

字典:

  1. 字典類型的簡寫語法:
    a.Dictionary <Key,Value>。b. [Key:Value]。其中Key表示字典中鍵的值的類型,Value表示存儲的值的類型。
    字典Key類型必須符合Hashable協議,就像集合的值類型一樣。
  2. 創建一個空的字典:
//方式一
let namesOfIntegers :Dictionary<Int,String> = Dictionary<Int,String>.init()
let namesOfIntegers  = Dictionary<Int,String>.init()
let namesOfIntegers  = Dictionary<Int,String>()

//方式二
let namesOfIntegers  = [Int:String].init() //!< [:]
let namesOfIntegers = [Int:String]()
//方式三:提供類型信息
let namesOfIntegers : [Int:String] = [:]

如果上下文已經提供了字典中的類型信息,則字典中的類型信息就是確定的。

  1. 創建帶初始值的字典:
let airports : [String:String] = [String:String].init(dictionaryLiteral: ("name","zhangfei"),("age","16"),("職業","將軍"))//!< ["職業": "將軍", "age": "16", "name": "zhangfei"]

簡寫語法:[key 1: value 1, key 2: value 2, key 3: value 3]

//鍵值類型都相同,swift樂行推斷,故省略字典類型
let airports = ["職業": "將軍", "age": "16", "name": "zhangfei"]
//以下類型的字典就不能類型推斷,必須聲明字典的鍵值類型
 let airports : [String : Any] = ["職業": "將軍", "age": 16, "name": "zhangfei"]
  1. 字典的訪問和修改
    count屬性:訪問字典鍵值對的個數。isEmpty屬性值Bool類型,字典判空
if airports.isEmpty {
    print("airports是空的")
} else {
    print("airports:\(airports)中有\(airports.count)個元素")//!< airports:["name": "zhangfei", "職業": "將軍", "age": "16"]中有3個元素
}

添加新項到字典中

//方式一.使用下標語法
var airports = ["job": "將軍", "age": "16", "name": "zhangfei"]
airports["sex"] = "男"
//方式二
var airports = ["job": "將軍", "age": "16", "name": "zhangfei"]
airports.updateValue("男", forKey: "sex")
print(airports)//!< ["sex": "男", "job": "將軍", "age": "16", "name": "zhangfei"]

更改與特定鍵關聯的值

//方式一.使用下標語法
var airports = ["job": "將軍", "age": "16", "name": "zhangfei"]
airports["job"] = "主公"
//方式二
var airports = ["job": "將軍", "age": "16", "name": "zhangfei"]
airports.updateValue("主公", forKey: "job")
print(airports)//!< ["age": "16", "job": "主公", "name": "zhangfei"]

上述示例中updateValue(_:forKey:)方法,若是key在字典中已存在,則更改其對應的值為新值,并且返回其對應的舊值。若key在字典中不存在,則返回nil,并且添加這個新的鍵值對到字典中,因為返回值可nil故此方法的返回值是可選類型。

if let oldValue =  airports.updateValue("男", forKey: "sex") {
    print("key早就已經存在了,并且舊值為\(oldValue)")
} else {
    print("key不存在,需添加到字典中")//!< log:key不存在,需添加到字典中
}

刪除字典中鍵值對:

//方式一.使用下標語法
var airports = ["job": "將軍", "age": "16", "name": "zhangfei"]
airports["job"] = nil
//方式二
if let value = airports.removeValue(forKey: "job") {
     print("The value \(value) was removed.")//!< The value 將軍 was removed.
}
print(airports)//!< ["age": "16", "name": "zhangfei"]

上述示例中removeValue(_:forKey:)方法,若是key在字典中已存在,則移除,并且返回該移除項的值。若key在字典中不存在,則返回nil,(不存在鍵值對,無法做移除)因為返回值可nil故此方法的返回值是可選類型。

  1. 字典的遍歷:
    使用for-in循環遍歷字典中的鍵值對。字典中的每項都會作為(key, value)這樣的元組類型返回,并且我們可以再迭代的過程中將元組的成員分解為臨時常量或變量。
//! 方式一
for item in airports {
print("\(item.key)")
print("\(item.value)")
}
//! 方式二
for (key,value) in airports {
print("\(key)")
print("\(value)")
}

單獨遍歷其鍵或值

for key in airports.keys {
    print(key)
}
for value in airports.values {
    print(value)
}

keysvalues的類型轉換為數組。不可強轉,類型不一致,需要重新初始化為Array類型

let keysArray = [String](airports.keys)
let valuesArray = Array<String>.init(airports.values)

Swift的Dictionary類型是無序的。要按特定順序遍歷字典的鍵或值,需要在字典的 keysvalues 屬性的基礎上使用sorted()方法(升序),得到有序的keys或values。

參考資料:
swift 5.1官方編程指南


推薦文章:
iOS 解析一個自定義協議
iOS13 DarkMode適配(二)
iOS13 DarkMode適配(一)
2019蘋果秋季新品發布會速覽
申請蘋果開發者賬號的流程
Sign In With Apple(一)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容

  • 集合類型 Swift提供三種主要的集合類型,稱為Array,Set和Dictionary,用于存儲值的集合。Arr...
    沐靈洛閱讀 398評論 0 3
  • 案例代碼下載 集合類型 Swift提供三種主要的集合類型,為數組,集合和字典,用于存儲集合值。數組是有序的值集合。...
    酒茶白開水閱讀 452評論 0 0
  • Swift 語言提供Arrays、Sets和Dictionaries三種基本的集合類型用來存儲集合數據。數組(Ar...
    窮人家的孩紙閱讀 581評論 3 2
  • Swift提供了三種主要的集合類型,array數組, set集合, dictionary字典,用于存儲值集合。數組...
    微笑中的你閱讀 542評論 0 0
  • 9月27日,中國女排在世界杯上3-1戰勝荷蘭隊,迎來九連勝,離冠軍又進一步。 她們目標明確,郎平教練在采訪時說出一...
    李祥鴻閱讀 75評論 0 1