//swift 提供三种集合类型 来存储集合数据
/*
Array Sets Dictionaries
数组 array 时有序数据的集,
集合Sets 是无序无重复数据的集
字典 dictionary 是无序的键值对的集
在存储数据时,对数据值得类型明确,不能把不正确的值插入其中,我们对取回的值的类型完全自信
如果将集合用变量分配,那集合就会是可变的,我们就可以添加和删除
如果是常量,那就是不可编辑的集合,内容,大小都不能改变
*/
/*
数组Arrays 数组使用有序列表存储同一类型的多个值,相同的值可以多次出现在一个数组的不同位置
Swift中 Array 类型被桥接到 Foundation 中的 NSArray类,
Swift 应该遵循 Array<Element>其中 Element 是这个数组中唯一允许存在的数据类型 。
也可以使用语法糖,[Element] 这样的简单语法,推荐语法糖来写
*/
//创建一个空数组
var someInts = [Int]()
print("someInts has \(someInts.count) items")
//someInts 被推断值为Int类型的集合
someInts.append(3)
//此时数组中增加了一个元素 好比oc 的 addobject
print(someInts)
someInts = []//设置数组为空 但someints 仍是Int类型的集合
print(someInts)
//swift 还提供一个可以创建特定大小并且所有数据都被默认的构造方法,我们可以吧准备加入新数组的数据项数量(count),和适当类型的初始值(repeating)传入数组构造函数
var threedoubles = Array(repeating: 0.0, count: 3)
print(threedoubles)
//通过两个数组相加创建一个数组
var testarr = [Any]()//不能写成 []()或 [] 在oc中可以 不确定类型用Any
// var newarr = threedoubles + testarr 报错 说testarr 不确定类型的数组
var doublearr = [1.1,1.2,1.3]
var newarr = threedoubles + doublearr
print(newarr)//打印输出结果 [0.0, 0.0, 0.0, 1.1000000000000001, 1.2, 1.3] 为什么会有1.100001?
// Decimal
var test1 = [Decimal](repeating: 0.1, count: 3)
var test = [Decimal]()
test = [1.1,1.2,1.3]
print(test)
//也可以这么写 stringarr 被声明为字符串值类型的数组,记为[string] 因此这个数组被规定只有string 一种数据类型结构,所以只有string 类型可以在其中被存取,在这里,stringarr由两个数组字面量定义
var stringarr : [String] = ["hello","world"]
//由于swift 的类型推断机制,当我们用字面量构造只拥有相同类型值数的时候,我们不必把数组的类型定义清除。
//只要初始的数组内所有的元素都是同一类型,那就该数组就会被推断为同一的类型数组
//访问数组 修改数组
// .count 访问数组个数 与oc一样
//用isEmpty 来判断是否为空数组
if stringarr.isEmpty{
print("空数组")
}else{
print("非空数组")
}
//与string 一样 用append 来追加和添加新数据项
stringarr.append("hello")
stringarr.append(contentsOf: ["666","777"]) //果然猜的没错 就是这么添加另一个数组
// stringarr.append(contentsOf: [1.1,2.2]) 报错 数据类型不对
print(stringarr)
//另一种追加语法糖
stringarr += ["追加"]
print(stringarr)
// stringarr -= ["追加"] 报错 -= 不能用在两个数组中
// print(stringarr)
//追加 不能用下标访问的形式去爱在数组尾部追加新项
//获取数组某一数据项 与oc 一样用下标方式
var firstone = stringarr[0] //获取第一个数据项
print(firstone)
for 字符串 in stringarr{
print(字符串,terminator:"-")
}
//取一个范围内的数据项
var arr = stringarr[2...4]
print(arr)
//插入数据项 用insert(_: at:)在某个具体的索引之前添加数据项
stringarr.insert("end", at: stringarr.count)//在个数之后追加 没问题
print(stringarr)
// stringarr.count == stringarr.endIndex 删除不能用count 和 endindex 下标
stringarr.remove(at: stringarr.endIndex-1)//在个数之后删除 会越界,下标为个数的地方没有值 超出了下标最大值
print(stringarr)
//在操作数组时,应该确保数组的有效性 数据项被移除后数组的空出项会被自动填补
//如果移除数组的最后一项 不应该用 remoe at 应该用removeLast()
stringarr.removeLast()//移除最后一个
stringarr.removeFirst()//移除第一个
//数组的遍历 使用for in 来遍历数据项
//如果我们同时需要每个数据项的值和索引值 可以使用enumerated()方法来进行数组遍历.
//enumerated() 返回一个每一个数据项索引值和数据值组成的元组。就是返回索引和元素
//注意是元组 所以 for 后加 () 括号里面是 下标和值
//在oc中用过这种方法,但不知道会返回索引 只认为是遍历数组的一种方式
for(index,value) in stringarr.enumerated(){
print(index,value)
}
//集合 Sets
//用来存储相同类型并且没有确定顺序的值,当集合元素顺序不重要时,或希望确保每个元素只出现一次时可以使用集合而不是数组
//Swift的Set类型被桥接到Foundation 中的NSSet类
/*集合类型的哈希值
一个类型为了存储在集合中,该类型必须是可哈希化的--也就是说,该类型必须提供一个方法来计算它的哈希值。一个哈希值是Int类型的,相等的对象哈希值必须相同,比如a==b 那么 a.hashvalue== b.hashvalue
Swift的所有基本类型(比如String,Int,double,bool)默认都是哈希化的,可以作为集合的值得类型或者字典的键的类型。没有关联值得枚举成员值(在枚举有讲述)默认也是可哈希化的
*/
/*
你可以使用你自定义的类型作为集合的值得类型 或者是字典的键的类型,但你需要使你的自定义的类型符合Swift标准库中的hashable协议。符合hashable协议的类型需要提供一个类型为Int的可读属性hashvalue。由类型的hashvalue属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。
*/
/*
因为hashable协议符合Equatable协议。所以遵循该协议的类型也必须提供一个“是否相等”运算符==的实现,这个Equatable协议要求任何符合 == 实现的实例间都是一种相等的关系。也就是说,对于abc三个值来说 == 的实现必须满足下面三种情况
*/
/*
a == a 自反性
a == b 意味着 b == a 对称性
a == b && b == c 意味着 a == c
*/
/*
集合类型语法
Swift 中的Set类型被写为Set<element> 这里的element 表示Set中允许存储的类型,和数组不同的是,集合没有等价的简化形式。md 就是没有语法糖呗,还没有等价的简化形式,不仔细想想都tm看不懂说的啥。
*/
var letters = Set<Character>()//空的集合
// var settest : Set = [Character]() 报错说不能转化为值类型在 Set上 说明语法糖不能用
print("letters is of type Set<character> with \(letters.count)")
//根据上下文提供了类型信息,比如作为函数的参数或者已知类型的变量或常量,我们可以通过一个空的数组字面量创建一个空的set
letters.insert("a")
print(letters)
let has = 1
// letters.insert(has.hashValue) 试试行不行 因为已经定义为character类型的集合了
letters = [] //这样才可以用语法糖置空,因为已经明确了类型
print(letters)
//用数组字面量创建集合
//可以使用数组字面量来构造集合,并且可以使用简化形式写一个或者多个值多为集合元素
//构造一个含有初始值的集合
var stringSet : Set<String> = ["hello","world","!"]
//一个set类型不能从数组字面量中被单独推断出来,因此set类型必须为显示声明,然而,由于Swift的类型推断功能,如果你想使用一个数组字面量构造一个set并且该数组字面量中的所有元素类型相同,那么就可以不用写出set的具体类型
var notype : Set = ["a","b","c"]//不能使用语法糖是错的 要加上指定的类型 set 后面才可以用语法糖
notype.isEmpty //是否为空
notype.count //个数
notype.insert("insert") //插入一个元素 不是数组 没有需要下标
print(notype)
notype.removeFirst()//删除第一个
print(notype)
// notype.removeAll()//删除所有
notype.removeAll(keepingCapacity: true)//有啥用? 我以为是删除后,保留删除前的所有元素开辟的空间,只是值不在了。更具arrayviewcapacity来看也是自动释放的意思
print(notype,notype.count)
var notype1 : Set = ["a","b","c"]
//通过删除一个元素,如果该值时set的一个元素则删除该元素,并且返回被删除的元素。如果set不包含则返回nil
if let removed = notype1.remove("a"){
print(removed,"移除a")
}else{
print("没有匹配任何值")
}
if notype1.contains("b"){
print("包含元素")
}else{
print("不包含")
}
for item in notype1{
print("\(item)")
}
let newSet : Set = ["1","2","3","4"]
let oldSet : Set = ["3","4","5","6"]
//取相同
let same = newSet.intersection(oldSet)
print(same)
//取除相同之外
let nosame = newSet.symmetricDifference(oldSet)
print(nosame)
//去重复
let quchong = newSet.union(oldSet)
print(quchong)
//取出除另一个所有
let noOther = newSet.subtracting(oldSet)
print(noOther)
//取出后的新集合是无序的
//只需在括号后 加 .sorted() 进行排序
let union = newSet.union(oldSet).sorted()
print(union)
//判断一个集合的值是否也在另一个集合中包含
//事实上 a只有部分被b包含 所以不行
if newSet.isSubset(of: oldSet){
print("a在b包含")
}else{
print("a不被b包含")
}
let a : Set = ["1","1"]
let b : Set = ["1","1","2","2"]//包含a
// let b : Set = ["1","2","2"]//包含a
if a.isSubset(of: b){
print("a在b包含")
}else{
print("a不被b包含")
}
//翻译的不明确,应为一个集合中的所有元素 都在另一个集合中出现过,可以用 isSubset(of:)
//一个集合是否完全包含另一个b
if a.isSuperset(of: b){
print("a完全包含b")
}else{
print("a不完全包含b")
}
let c : Set = ["2","3","4"]
//使用 isStrictSubset(of:) isStrictSuperset(of:) 来判断一个集合是否是另一个集合的自己和或父集合 并且两个集合不相等
let q : Set = ["1","2"]
let w : Set = ["1","2"]
print(q.isSubset(of: w))//q是否被w包含 true
print(q.isSuperset(of: w))//q 是否包含w true
print(q.isStrictSubset(of: w))//q是否是w 的子集合 false
print(q.isStrictSuperset(of: w))//q是否是w的父集合 false
let x : Set = ["1","2"]
let y : Set = ["1","2","3"]
print(x.isSubset(of: y))//q是否被w包含 true
print(x.isSuperset(of: y))//q 是否包含w false
print(x.isStrictSubset(of: y))//q是否是w 的子集合 true
print(x.isStrictSuperset(of: y))//q是否是w的父集合 false
//使用isDisjoint(with:) 来判断两个集合是否不包含有相同的值(是否没有交集)
//字典 Swift的Dictionary 类型被桥接到Oc 的 NSDictionary类
//一个字典的key 必须遵循hashable协议 就想Set的值类型
//定义时,可以用dictionary<key,Value> 或者 语法糖 [key:value]
//创建一个空字典
var dict = [Int : String]()
dict = [1:"1",2:"2"]
print(dict)
//其中 4 是key 非下标
dict[4] = "2" //没有使用增加方法 ,直接指定一个key设置上值 就新增了一个键值对
print(dict)
//在定义的时候不能用[:] 置为空的时候可以使用
dict = [:]
print(dict)
var airport : [String : String] = ["where":"beijing","money":"1000"]
//如果在构造字典时 如果每个值 或者 每个键 都是同一类型 就不需要定义类型
//使用isEmpty 来检查count 是否为0
//使用count 来获取字典的数据项个数
airport["haha"] = "xixi" //指定某个键为某个值
print(airport)
airport["where"] = "上海" //通过key来修改该key所对应的值
//作为另一种下标方法,字典的updatevalue(_:forkey:) 方法可以设置或者更新特定键对应的值。就想上面所示的下标示例,updatevalue(_:forkey:)方法在这个键不存在对应值得时候会设置新值或者在存在时更新已存在的值,和上面的下标方法不同的,updatevalue(_:forkey:)这个方法返回更新值之前的原值,这样使得我们可以检查更新是否成功
//updatevalue 方法会返回对应值得类型的可选值 对于存储string 值得字典,这个函数会返回一个string? 或者 可选string类型的值
//如果有值存在于更新前,则这个可选值包含了旧值,否则它将会是nil
if let oldvalue = airport.updateValue("haha", forKey: "haha"){
print("oldvalue is \(oldvalue)") //执行 有 haha key 返回haha 之前的值
}else{
print("nil")
}
print(airport["lala"])//访问该key对应 的值,若key对应的值不存在 返回nil
if let newvalue = airport.updateValue("haha", forKey: "lala"){
print("oldvalue is \(newvalue)")
}else{
print("nil") //执行 因为没有lala 这个key
}
//removevalue(forkey:)方法也可以用来在字典中移除键值对,这个方法在键值对存在的情况下会移除该键值对并且返回被移除的值或者在没有值的情况下返回nil
if let value = airport.removeValue(forKey: "money"){
print(value) //执行 有money key 返回money key之前的值
}else{
print("no key money")
}
print(airport)
//字典遍历
var json = ["1":"one","2":"two","3":"three","4":"four","5":"five"]
for (jsonkey,jsonvalue) in json{
print("\(jsonkey),\(jsonvalue)")
}
for key in json.keys{
print(key)
}
for value in json.values{
print(value)
}
//swift 的字典类型是无序的的集合类型 。为了以特定的顺序遍历字典的键或值,可以对字典的keys或者values属性使用Sorted()方法
for sortedkey in json.keys.sorted(){
print(sortedkey)
}
for sortedvalue in json.values.sorted(){
print(sortedvalue)
}
var jsonChinese = ["安徽":"one","重庆":"two","安阳":"three","蚌埠":"four","支付宝":"five"]
for sortedkey in jsonChinese.keys{
print(sortedkey)
}
for sortedvalue in jsonChinese.keys.sorted(){
print(sortedvalue)
}
//然而对中文并没有什么乱用 白高兴一场 如果key是英文的话 会按英文的字母顺序来排
输出为
someInts has 0 items
[3]
[]
[0.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 1.1000000000000001, 1.2, 1.3]
[1.1, 1.2, 1.3]
非空数组
["hello", "world", "hello", "666", "777"]
["hello", "world", "hello", "666", "777", "追加"]
hello
hello-world-hello-666-777-追加-["hello", "666", "777"]
["hello", "world", "hello", "666", "777", "追加", "end"]
["hello", "world", "hello", "666", "777", "追加"]
0 world
1 hello
2 666
3 777
letters is of type Set<character> with 0
["a"]
[]
["b", "insert", "a", "c"]
["insert", "a", "c"]
[] 0
a 移除a
包含元素
b
c
["3", "4"]
["2", "1", "6", "5"]
["4", "2", "1", "5", "6", "3"]
["2", "1"]
["1", "2", "3", "4", "5", "6"]
a不被b包含
a在b包含
a不完全包含b
true
true
false
false
true
false
true
false
[2: "2", 1: "1"]
[2: "2", 4: "2", 1: "1"]
[:]
["money": "1000", "haha": "xixi", "where": "beijing"]
oldvalue is xixi
nil
nil
1000
["haha": "haha", "where": "上海", "lala": "haha"]
4,four
2,two
1,one
5,five
3,three
4
2
1
5
3
four
two
one
five
three
1
2
3
4
5
five
four
one
three
two
安阳
支付宝
蚌埠
安徽
重庆
安徽
安阳
支付宝
蚌埠
重庆