Swift 4.0学习之旅—集合类型

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

推荐阅读更多精彩内容