Swift集合类型_4

Swift提供了三种基本集合类型:Arrays Sets Dictionaries用来储存集合数据,数组(Arrays)是有序数据的集,集合(Sets)是无序无重复数据的集,字典(Dictionaries)是无序的键值对的集

Swift 语言中的ArraysSetsDictionaries中存储的数据值类型必须明确。这意味着我们不能把不正确的数据类型插入其中。同时这也说明我们完全可以对取回值的类型非常自信

集合的可变性

如果创建Arrays Sets Dictionaries并且把它分配成一个变量,那么这个集合相当于oc中的可变集合,我们可以对他进行增删改等操作,但是如果把他们分配成常量,那么它的大小和内容是不能被改变的

在我们不需要改变集合的时候创建不可变集合是很好的实践

数组(Arrays)

数组使用序列表储存同一类型的多个值,相同的值可以多次出现在数组的不同位置中

写swift数组应该遵守Array<Element>这样的形式,期中Element是这个数组中唯一允许存在的数据类型,我们也可以使用[Element]这样简单的语法

创建一个空的数组
//创建一个空的数组
var emptyArr = Array<Int>()
var emptyArr2 = [Int]()

因此empty的类型就被推断为[Int]

或者,如果代码上下文中已经提供了类型信息,例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:[](一对空方括号):

//创建一个
emptyArr2.append(3)
// someInts 现在包含一个 Int 值
emptyArr2 = []
// someInts 现在是空数组,但是仍然是 [Int] 类型的。
创建一个带有默认值的数组

Swift 中的Array类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(count)和适当类型的初始值(repeating)传入数组构造函数

var arr3 = Array(repeating:0.4,count:5)
print(arr3)
//result:[0.4,0.4,0.4,0.4,0.4]
//可以知道arr3是一种[Double]数组,等价于[0.4,0.4,0.4,0.4,0.4]
通过两个数组想加创建一个数组

我们可以使用加法操作符(+)来组合两种已存在的相同类型数组。新数组的数据类型会被从两个数组的数据类型中推断出来

//通过两个数组相加创建一个数组,两个数组的类型必须相同
var arr4 = [0.8,0.8,0.8,0.8]
var arr5 = arr3+arr4
//result:[0.4, 0.4, 0.4, 0.4, 0.4, 0.8, 0.8, 0.8, 0.8]
用数组字面量构造数组

我们可以使用数组字面量来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。数组字面量是一系列由逗号分割并由方括号包含的数值

var arr7 :[String] = ["do","you","remember"]
//因为这个数组被规定只有String一种数据结构,所以只有String类型可以在其中被存取
var arr6 = ["i","am","superboy"]
//由于 Swift 的类型推断机制,当我们用字面量构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚
修改和访问数组

-获取数组的个数

//获取数组的数量
print("arr6的个数 (\(arr6.count))")
//result:3

-判断数组是否为空

var arr8 = [Int]()
print("arr8是否为空\(arr8.count)  \(arr8.isEmpty)")
//result:arr8是否为空0  true

-增

//增
var arr9 = ["you","are","my"]
//追加
arr9.append("sunshine")
//也可以直接在数组后面添加一个或多个拥有相同类型的数据项
arr9 += ["do"]

-改

 var arr10 = ["edison","is","god","yes"]
arr10[0] = "yaowei"
print("arr10:(\(arr10)")
//result:["yaowei", "is", "god", "yes"]

//还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的,但是不能超过数组的下标操作,否则报错(Array index is out of range)
var arr11 = ["one","more","try","again"]
arr11[1...3] = ["ok","joke"]
print("arr11:(arr11)")
//result:arr11:["one", "ok", "joke"]

-插

var arr12 = [1,2,3,4,5,6]
arr12 .insert(7, at: arr12.endIndex)
arr12.insert(5, at: 3)
arr12.insert(0, at: arr12.startIndex)
//result:[0, 1, 2, 3, 5, 4, 5, 6, 7]

-删
remove

var arr13 = [1,2,3,4,5,6,7];
arr13.remove(at: 2)
数组的遍历

//数组的遍历

var arr14 = ["i","am","handsome","man"]
for st in arr14 {
    print("\(st)")
}
/*
 i
 am
 handsome
 man
 */

如果我们同事需要每个数据项的值和索引值,可以使用enumerated()方法来进行遍历,enumerated()返回一个由每一个数据项索引值和数据值组成的元组。我们可以把这个元组分解成临时常量或者变量来进行遍历

for (idx,value) in arr14.enumerated() {
    print("idx:\(idx),value:\(value)")
}
/*
 idx:0,value:i
 idx:1,value:am
 idx:2,value:handsome
 idx:3,value:man
 */

集合(Sets)

集合(Set)用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组

集合类型的哈希值

一个类型为了储存在集合中,该类型必须是可哈希化的,也就是说,改类型必须提供一个方法来计算它的哈希值,一个哈希值是Int类型的,相等的对象哈希值必须相同,比如a==b,因此a.hashValue==b.hashValue
Swift 的所有基本类型(比如String,Int,DoubleBool)默认都是可哈希化的,可以作为集合的值的类型或者字典的键的类型

你可以使用你自定义的类型作为集合的值的类型或者是字典的键的类型,但你需要使你的自定义类型符合 Swift 标准库中的Hashable协议。符合Hashable协议的类型需要提供一个类型为Int的可读属性hashValue。由类型的hashValue属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。

因为Hashable协议符合Equatable协议,所以遵循该协议的类型也必须提供一个"是否相等"运算符(==)的实现。这个Equatable协议要求任何符合==实现的实例间都是一种相等的关系。也就是说,对于a,b,c三个值来说,==的实现必须满足下面三种情况:

a == a(自反性)
a == b意味着b == a(对称性)
a == b &&b == c意味着a ==c(传递性)

集合类型语法

Swift中Set类型被写成Set[Element],这里的Element表示Set中允许存储的类型,和数组不同的是,集合没有等价的简化形式

创建空的集合

//创建一个空的集合

var set1 = Set<Int>()

var set2:Set<Int> = [1,2,3,4,5]

var set3:Set = [4,5,6,7,8]

var set4:Set = ["f","c","y","y"]

一个Set类型不能从数组字面量中被单独推断出来,因此Set类型必须显式声明。然而,由于 Swift 的类型推断功能,如果你想使用一个数组字面量构造一个Set并且该数组字面量中的所有元素类型相同,那么你无须写出Set的具体类型

访问和修改一个集合

-跟数组一样可用countisEmpty
-增加元素

//添加
var set5:Set = [1,2,3,4,5,6,7,8]
set5.insert(9)
print("set5:\(set5)")
//result:[2, 4, 9, 5, 6, 7, 3, 1, 8]
var set6:Set = ["q","w","e","r"]
set6.insert("t")
print("set6:\(set6)")
//result:["e", "w", "q", "r", "t"]

-删除
你可以通过调用Setremove(_:)方法去删除一个元素,如果该值是该Set的一个元素则删除该元素并且返回被删除的元素值,否则如果该Set不包含该值,则返回nil。另外,Set中的所有元素可以通过它的removeAll()方法删除

//删
set6.remove("q")
print("set6:\(set6)")
//result:["e", "w", "r", "t"]

-遍历一个集合

//遍历一个集合
for idx in set5 {
    print("idx=\(idx)")
}
/*
 idx=2
 idx=4
 idx=9
 idx=5
 idx=6
 idx=7
 idx=3
 idx=1
 idx=8
 */

SwiftSet类型没有确定的顺序,为了按照特定顺序来遍历一个Set中的值可以使用sorted()方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符'<'对元素进行比较的结果来确定

for st2 in set6.sorted() {
    print("st2:\(st2)")
}
/*
 st2:e
 st2:r
 st2:t
 st2:w
 */
集合操作

你可以高效地完成Set的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交
-使用intersection(_:)方法根据两个集合中都包含的值创建的一个新的集合

//根据两个集合中都包含的值创建的一个新的集合
var set7_1:Set = ["you","me","she"]
var set7_2:Set = ["me","ye","you"]
var set7_3:Set = set7_1.intersection(set7_2)
print("两个集合的交集:(\(set7_3)")
//result:两个集合的交集:(["you", "me"]

-使用symmetricDifference(_:)方法根据在一个集合中但不在两个集合中的值创建一个新的集合

var set7_4:Set = set7_1.symmetricDifference(set7_2)
print("两个集合的不想交交集:(\(set7_4)")
//result:两个集合的不想交交集:(["she", "ye"]

-使用union(_:)方法根据两个集合的值创建一个新的集合

//根据两个集合的值创建一个新的集合
var set7_5:Set = set7_1.union(set7_2)
print("两个集合的总共值:(\(set7_5)")
//result:两个集合的总共值:(["you", "she", "me", "ye"]

-使用subtracting(_:)方法根据不在该集合中的值创建一个新的集合

集合成员关系和相等
  • 使用“是否相等”运算符(==)来判断两个集合是否包含全部相同的值
//使用“是否相等”运算符(==)来判断两个集合是否包含全部相同的值
var set8_1:Set = ["you","me","she"]
var set8_2:Set = ["me","ye","you"]
print((set8_1==set8_2 ? "相等" : "不相等"))
//result:不相等
var set8_3:Set = ["you","me"]
var set8_4:Set = ["me","you"]
print((set8_3==set8_4 ? "相等" : "不相等"))
//result:相等
  • 使用isSubset(of:)方法来判断一个集合中的值是否也被包含在另外一个集合中
  • 使用isSuperset(of:)方法来判断一个集合中包含另一个集合中所有的值
  • 使用isStrictSubset(of:)或者isStrictSuperset(of:)方法来判断一个集合是否是另外一个集合的子集合或者父集合并且两个集合并不相等
  • 使用isDisjoint(with:)方法来判断两个集合是否不含有相同的值(是否没有交集)

字典

字典是一种存储多个相同类型的值的容器。每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。和数组中的数据项不同,字典中的数据项并没有具体顺序。我们在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样

字典类型简化语法

swift的字典使用Dictionary<key,value>定义,也可以使用[key:value]这样的简化形式去创建一个字典类型,推荐用后者简化形式

注意,一个字典的key类型必须遵守Hashable协议,就像set的值类型

创建一个空字典
//创建一个空的字典
var dic1 =  Dictionary<Int,String>()
var dic2 =  [Int:String]()

这个就是创建了[Int:String]类型的空字典来储存整数的英语命名,它的键的类型是Int,值的类型String

定义字典
var dic3 = [1:"1",2:"2",3:"3",4:"4"]
var dic4:[String:String] = ["q":"q","w":"w","e":"e"]
访问和修改字典
  • 同理可以使用countisEmpty来获取字典的数量以及是否为空

//增加
dic4["r"] = "r"
print("after add dic4=\(dic4)")
//result:after add dic4=["e": "e", "w": "w", "q": "q", "r": "r"]
//增加了["r":"r"]

  • 可以使用下标语法来改变指定键对应的值
//改
dic4["q"]="q2"
print("after change dic4=\(dic4)")
//after change dic4=["e": "e", "w": "w", "q": "q2", "r": "r"]
//原本键'q':"q" 现在键:"q":"q2"

作为另一个下标方法,字典的updateValue(_:forKey:)方法可以设置或者更新特定键对应的值。就像上面所示的下标示例,updateValue(_:forKey:)方法在这个键不存在对应值的时候会设置新值或者在存在时更新已存在的值。和上面的下标方法不同的,updateValue(_:forKey:)这个方法返回更新值之前的原值。这样使得我们可以检查更新是否成功
updateValue(_:forKey:)方法会返回对应值的类型的可选值。举例来说:对于存储String值的字典,这个函数会返回一个String?或者“可选 String”类型的值
如果有值存在于更新前,则这个可选值包含了旧值,否则它将会是nil

if let oldValue = dic4.updateValue("q5", forKey: "q") {
    print("after change dic4 suc  oldValue:\(oldValue)")
}
else{
    print("after change dic4 fai ")
}

if let oldValue = dic4.updateValue("q5", forKey: "q") {
    print("after change dic4 suc  oldValue:\(oldValue)")
}
else{
    print("after change dic4 fai ")
}
if let oldValue = dic4.updateValue("q5", forKey: "q") {
    print("after change dic4 suc  oldValue:\(oldValue)")
}
else{
    print("after change dic4 fai ")
}
/*
 after change dic4 suc  oldValue:q2
 after change dic4 suc  oldValue:q5
 after change dic4 suc  oldValue:q5

*/

我们也可以使用下标语法来在字典中检索特定键对应的值。因为有可能请求的键没有对应的值存在,字典的下标访问会返回对应值的类型的可选值。如果这个字典包含请求键所对应的值,下标会返回一个包含这个存在值的可选值,否则将返回nil

if let dic4Value = dic4["q"] {
    print("dic4 key  q: \(dic4Value)")
}
else{
    print("dic key q : nil")
}
//reslut:dic4 key  q: q5
  • 移除

我们还可以使用下标语法来通过给某个键的对应值赋值为nil来从字典里移除一个键值对

//移除
dic4["q"] = nil
print("after remove dic4:\(dic4) ")
//result:after remove dic4:["e": "e", "w": "w", "r": "r"]  没有q了

此外,removeValue(forKey:)方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的值或者在没有值的情况下返回nil:

if let removeSuc = dic4.removeValue(forKey: "e") {
    print("after remove2 dic4:\(dic4)  removeSuc:\(removeSuc)")
}
else{
    print("after remove2 dic4:\(dic4)  没有这个 e")
}
//result:after remove2 dic4:["w": "w", "r": "r"]  removeSuc:e

字典遍历

我们可以使用for-in循环来遍历某个字典中的键值对。每一个字典中的数据项都以(key, value)元组形式返回,并且我们可以使用临时常量或者变量来分解这些元组

//字典遍历
for (dicKey,dicValue) in dic4 {
    print("key:\(dicKey) value:\(dicValue)")
}
/*
 result:
 
 key:w value:w
 key:r value:r
 */

也可以通过访问keys或者values属性,来遍历


for dicKey in dic4.keys {
    print("keys:\(dicKey)")
    print("forvalue:\(String(describing: dic4[dicKey]))")
//    if let valueforkey = dic4[dicKey] {
//        print("for value:\(String(describing: dic4[valueforkey]))")
//    }
    
}

/*
 keys:w
 keys:r
 */
for dicValues in dic4.values {
    print("values:\(dicValues)")
}
/*
 values:w
 values:r
 */

如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受Array实例的 API 的参数,可以直接使用keys或者values属性构造一个新数组:

let dic4Keys = [String](dic4.keys)
let dic4Values = [String](dic4.values)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容