Swift提供了三种基本集合类型:Arrays
Sets
Dictionaries
用来储存集合数据,数组(Arrays
)是有序数据的集,集合(Sets
)是无序无重复数据的集,字典(Dictionaries
)是无序的键值对的集
Swift 语言中的Arrays
、Sets
和Dictionaries
中存储的数据值类型必须明确。这意味着我们不能把不正确的数据类型插入其中。同时这也说明我们完全可以对取回值的类型非常自信
集合的可变性
如果创建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
,Double
和Bool
)默认都是可哈希化的,可以作为集合的值的类型或者字典的键的类型
你可以使用你自定义的类型作为集合的值的类型或者是字典的键的类型,但你需要使你的自定义类型符合
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
的具体类型
访问和修改一个集合
-跟数组一样可用count
和isEmpty
-增加元素
//添加
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"]
-删除
你可以通过调用Set
的remove(_:)
方法去删除一个元素,如果该值是该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
*/
Swift
的Set
类型没有确定的顺序,为了按照特定顺序来遍历一个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"]
访问和修改字典
同理可以使用
count
和isEmpty
来获取字典的数量以及是否为空增
//增加
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)