Swift 数组、字典和集合

Swift 数组、字典和集合,第1张

概述前言 Swift语言提供Array、Set和Dictionary三种基本的集合类型用来存储集合数据。数组是有序的数据集;集合是无序无重复的数据集;而字典是无序的键值对数组集。 Swift的Array、Set和Dictionary类型被实现为泛型集合。因此,它所存储的元素的类型必须是一致的,同样,我们取出来的数据类型也是明确的。 集合的可变性(Mutability Of Collections) 如 前言

Swift语言提供Array、Set和Dictionary三种基本的集合类型用来存储集合数据。数组是有序的数据集;集合是无序无重复的数据集;而字典是无序的键值对数组集。

Swift的Array、Set和Dictionary类型被实现为泛型集合。因此,它所存储的元素的类型必须是一致的,同样,我们取出来的数据类型也是明确的。

集合的可变性(Mutability Of Collections)

如果创建一个Arrays、Sets或DictionarIEs并且把它分配成一个变量,这个集合将会是可变的。这意味着我们可以在创建之后添加更多或移除已存在的数据项,或者改变集合中的数据项。

如果我们把Arrays、Sets或DictionarIEs分配成常量,那么它就是不可变的,它的大小和内容都不能被改变。

若我们确定集合不需要改变,那么我们应该使用不可变集合,也就是使用let声明,那样编译器会为我们优化。

<code  Source Code Pro",monospace;Font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span  >// 在swift中要让Array、Set、Dictionary类型的变量是可变的,用var声明就可以了。</span><span  >// 如果不希望可变,用let声明即可。</span><span  >let</span> immutableArrray = [Int]()<span  >// 提示:error: immutable value of type '[Int]' only has mutating</span><span  >// members named 'append'</span><span  >//immutableArrray.append(12)</span><span  >// OK</span><span  >var</span> mutableArray = [Int]()mutableArray.append(<span  >12</span>)</code><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li></ul><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li></ul>
数组(Arrays)

数组使用有序列表存储同一类型的多个值,相同的值可以多次出现在一个数组的不同位置中。我们需要明确,数组是有序的,元素类型是相同的。

Swift中的Array与Foundation中的NSArray是桥接的,可以相互转换。

创建一个空数组(Create An Empty Array)

由于Swift中的数组是泛型,因此必须指定元素的数据类型:

<code  Source Code Pro",0); Box-sizing: border-Box;">// 使用构造语法来创建一个由特定数据类型构成的空数组:</span><span  >// 方括号中必须指定类型,因为Array是一种泛型</span><span  >var</span> emptyArray = [Int]()<span  >// 也可以使用结构体Array的构造写法</span><span  >var</span> anotherEmptyArray = <span  >Array</span><Int>()<span  >// 如果之前类型明确了,直接再用[]即可.一样是Int类型的元素,是可推断出来的</span>emptyArray = []</code><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li></ul><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li></ul>
创建带默认值的数组(Creating An Array With A Default Value)

Swift提供了如下方法,可以创建带有默认值的数组,这个构造方法是使用count个指定元素来初始化:

 

例如:

<code  Source Code Pro",monospace;Font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">var threeDoubles = [<span  >Double</span>](<span  >count: 3,repeatedValue:0.0</span>)// threeDoubles 是一种 [Double] 数组,等价于 [0.0,0.0,0.0]</code><ul  ><li >1</li><li >2</li></ul><ul  ><li >1</li><li >2</li></ul>
数组相加来创建数组(Creating An Array By Adding Two Array Togeter)

两个数组能够通过加号+来创建一个合并的数组,是因为苹果为我们提供了这样的方法:

<code  Source Code Pro",monospace;Font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">public func +<RRC1 : RangeReplaceableCollectionType,RRC2 : RangeReplaceableCollectionType where RRC1<span  >.Generator</span><span  >.Element</span> == RRC2<span  >.Element</span>>(lhs: RRC1,rhs: RRC2) -> RRC1</code><ul  ><li >1</li></ul><ul  ><li >1</li></ul>

这是个泛型函数,要求类型RRC1和RRC2是遵守RangeReplaceableCollectionType协议的,并且这两个集合的元素类型要求相同。而数组是遵守RangeReplaceableCollectionType协议的,因此可以通过此方法将两个数组相加。

例如:

  用数组字面量构造数组(Creating An Array With An Array literal) 

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

 

由于类型是明确的,因此我们可以交由编译器来推断类型数组的类型:

  访问和修改数组(Accessing And Modifying An Array) 

常见的数组访问和修改 *** 作有:

获取数组元素个数 判断数组是否为空 数组追加元素 数组在某个位置插入元素 数组在某个范围插入元素 数组元素个数

获取数组元素的个数,可通过count属性获取:

<code  Source Code Pro",monospace;Font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">// 打印结果:<span  >"The shopPing List contains 2 items."</span><span  ><span  >print</span><span  >(<span  >"The shopPing List contains \(shopPingList.count) items."</span>)</span></span></code><ul  ><li >1</li><li >2</li></ul>
数组判断是否为空

判断数组是否为空,可以通过isEmpty属性判断,也可以通过count判断:

<code  Source Code Pro",136); Box-sizing: border-Box;">if</span> shopPingList.isEmpty {    <span  >print</span>(<span  >"The shopPing List is empty."</span>)} <span  >else</span> {    <span  >"The shopPing List is not empty."</span>)}<span  >// 或者通过count属性</span><span  >if</span> shopPingList.count == <span  >0</span> {    <span  >"The shopPing List is not empty."</span>)}</code><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li></ul><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li></ul>
数组末尾追加元素

常用的有以下几种方法:

通过append()追加 通过appendContentsOf()追加 通过+=追加

我们先来分析一下数组结构体所提供的方法:

 

我们可以看到对于第一个appendContentsOf方法要求参数S是遵守了SequenceType

 数组插入元素 

数组提供了insert(_:at:)方法插入数据:

<code  Source Code Pro",monospace;Font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">/// <span  ><span  >Insert</span> <span  >`newElement`</span> <span  >at</span> index <span  >`i`</span>.////// - Requires: <span  >`i <= count`</span>.////// - Complexity: O(<span  >`count`</span>).<span  >public</span> mutating func <span  >insert</span>(newElement: Element,atIndex i: <span  >Int</span>)</span></code><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li></ul><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li></ul>

那么可以通过调用来插入数据:

 数组修改值 

我们也可以通过下标获取或者修改数据,我们先看看声明:

<code  Source Code Pro",monospace;Font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span  >//</span> 这个方法是在index位置插入数据或者获取index位置的数据public subscript <span  ><span  >(index: Int)</span> -></span> Element<span  >//</span> 这个方法是在指定的range插入多个数据或者获取指定range的数据public subscript <span  ><span  >(subRange: Range<Int>)</span> -></span> ArraySlice<Element></code><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li></ul>

通过下标获取或者修改值:

 

也可以调用replaceRange(_:with:)来替换值:

<code  Source Code Pro",monospace;Font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span  >array</span>.replaceRange(<span  >.2</span>,<span  >with</span>: [<span  >10</span>,102); Box-sizing: border-Box;">12</span>])</code><ul  ><li >1</li></ul>
数组移除元素

先看看苹果所提供的方法:

<code  Source Code Pro",0); Box-sizing: border-Box;">// 移除最后一个元素</span><span  >public</span> mutating func removeLast() -> Element<span  >// 某个指定位置的元素</span><span  >public</span> mutating func removeAtIndex(<span  >index</span>: Int) -> Element<span  >// 移除某个范围</span><span  >public</span> mutating func removeRange(subRange: Range<<span  >Self</span>.<span  >Index</span>>)<span  >// 移除前n个</span><span  >public</span> mutating func removeFirst(n: Int)<span  >// 移除第一个</span><span  >public</span> mutating func removeFirst() -> <span  >Self</span>.Generator.Element<span  >// 清空</span><span  >public</span> mutating func removeAll(keepCapacity keepCapacity: Bool = <span  >default</span>)</code><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li><li >13</li><li >14</li><li >15</li><li >16</li><li >17</li></ul><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li><li >13</li><li >14</li><li >15</li><li >16</li><li >17</li></ul>

看看如何调用:

<code  Source Code Pro",0); Box-sizing: border-Box;">// 删除第一个</span><span  >let</span> element <span  >=</span> <span  >array</span><span  >.</span>removeAtIndex(<span  >0</span>)<span  >// 删除最后一个</span><span  >let</span> lastElement <span  >.</span>removeLast()<span  >// 删除所有元素,但是内存不释放,空间容量保留</span><span  >.</span>removeAll(keepCapacity: <span  >true</span>)<span  >// 删除所有元素,且不保留原来的空间</span><span  >false</span>)<span  >// 移除位置1、2、3的元素</span><span  >.</span>removeRange(<span  >1.</span><span  >..</span><span  >// 移除第一个元素</span><span  >let</span> first <span  >.</span>removeFirst()<span  >// 移除前三个元素</span><span  >.</span>removeFirst(<span  >3</span>)</code><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li><li >13</li><li >14</li><li >15</li><li >16</li><li >17</li><li >18</li><li >19</li><li >20</li></ul><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li><li >13</li><li >14</li><li >15</li><li >16</li><li >17</li><li >18</li><li >19</li><li >20</li></ul>
数组遍历

常用的数组遍历有几种。

第一种,只获取元素值的for-in遍历:

<code  Source Code Pro",136); Box-sizing: border-Box;">for</span> <span  >item</span> <span  >in</span> array {    print(<span  >item</span>)}</code><ul  ><li >1</li><li >2</li><li >3</li></ul>

第二种,获取元素及索引的for-in遍历:

 集合(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(传递性) 空集合(Empty Set)

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

  初始化集合(Initializing An Empty Set) 

可以直接使用数组字面量来初始化集合:

 

使用集合可以非常好地解决重复问题:

  访问集合(Accessing A Set) 

获取集合元素的个数,可以通过count只读属性获取,其时间复杂度为O(1),也就是常量,因此效率是极高的。想想时间复杂度能达到O(1),说明内部并不是列表,而是类似字典那样的哈希表,不过具体内部是如何,这里不细说,还得去查看源代码才能知晓。

 

调用就很方便了,效率又非常地高:

<code  Source Code Pro",monospace;Font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">let <span  >count</span> = favSet.<span  >count</span></code><ul  ><li >1</li></ul>

我们还可以通过isEmpty属性判断是否为空:

 

判断元素是否在集合中:

  遍历集合(Iterating Over A Set) 

遍历很少能离开得了for-in语法:

 

遍历集合,同时使集合是有序的:

 

当然还可以使用最原始的方法来遍历:

<code  Source Code Pro",136); Box-sizing: border-Box;">for</span> var <span  >i</span> = <span  >favSet.</span>startIndex; <span  >i</span> != <span  >favSet.</span>endindex; <span  >i</span> = <span  >i.</span>successor() <span  >{  print("for-i-in" + favSet[i])}</span></code><ul  ><li >1</li><li >2</li><li >3</li></ul>
集合基本 *** 作(Fundamental Set Operations)

集合的基本 *** 作有:

求交集:使用intersect(_:)方法根据两个集合中都包含的值创建的一个新的集合。 求非交集:使用exclusiveOr(_:)方法根据在一个集合中但不在两个集合中的值创建一个新的集合。 求并集:使用union(_:)方法根据两个集合的值创建一个新的集合。 求差集:使用subtract(_:)方法根据不在该集合中的值创建一个新的集合。

<code  Source Code Pro",102); Box-sizing: border-Box;">let</span> <span  >set</span>1: Set = [<span  >2</span>,102); Box-sizing: border-Box;">5</span>]<span  >set</span>2: Set = [<span  >8</span>]// 求两个集合的交集// <span  >4</span>print(<span  >set</span>1.intersect(<span  >set</span>2))// 求两个集合的并集// <span  >5</span>print(<span  >set</span>1.union(<span  >set</span>2).sort())// 求集合<span  >set</span>1去掉<span  >set</span>1与<span  >set</span>2的交集部分// <span  >set</span>1.subtract(<span  >set</span>2的并集 去掉 集合<span  >set</span>2的交集 部分// <span  >5</span>,102); Box-sizing: border-Box;">8</span>print(<span  >set</span>1.exclusiveOr(<span  >set</span>2).sort())</code><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li><li >13</li><li >14</li><li >15</li><li >16</li><li >17</li><li >18</li></ul><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li><li >13</li><li >14</li><li >15</li><li >16</li><li >17</li><li >18</li></ul>
集合成员关系(Relationships Of Set members) 使用\==来判断两个集合是否包含全部相同的值。 使用isSubsetof(_:)方法来判断是否为子集 使用isSupersetof(_:)方法来判断是否为超集 使用isstrictSubsetof(_:)或者isstrictSupersetof(_:)方法来判断一个集合是否是另外一个集合的子集合或者父集合并且两个集合并不相等。 使用isdisjointWith(_:)方法来判断两个集合是否不含有相同的值。

从图中可以看出:

集合a全部包含b,也就是说b是a的子集 集合a与集合b相交,但是a与b不完全包含 集合c与集合b完全没有交集
 字典(DictonarIEs) 

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

Swift中的Dictionary与Foundation中的NSDictionary是桥接的,可以互相转换使用。

我们先来看看字典的结构定义:

 

它是基于哈希表从key到value实例的映射,它的键值是无序的。要求key是遵守Hashable的。
其正规语法应该是:Dictonary<key,value>

创建空字典(Creating An Empty Dictionary)
  初始化字典(Initializing A Dictionary) 
 

声明不可变字典:

  访问和修改字典(Accessing And Modifying A Dictionary) 

我们可以通过字典的方法和属性来访问和修改字典,或者通过使用下标语法。

判断是否为空字典:

 

可以直接通过下标获取元素:

 

可以直接通过下标来修改或者增加值:

 

移除元素:

<code  Source Code Pro",0); Box-sizing: border-Box;">// 通过下标语法移除元素</span>dict[<span  >"D"</span>] = <span  >nil</span><span  >// 或者通过调用removeValueForKey方法来移除</span><span  >if</span> let removedValue = dict.removeValueForKey(<span  >"D"</span>) {  <span  >print</span>(<span  >"The removed value is \(removedValue)"</span>)} <span  >else</span> {  <span  >"The key D doesn'\t exist in dict,can\' be removed."</span>)}<span  >// 或者清空字典:</span>dict.removeAll()</code><ul  ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li></ul>
字典遍历(Iterate Over A Dictionary)

字典中每个元素是一个键值对,而这个键值对其实就是一个元组:

 

可以通过遍历所有的key:

<code  Source Code Pro",0); Box-sizing: border-Box;">// 可以遍历key</span><span  >for</span> key <span  >in</span> dict.keys {  <span  >"\(key): \(dict[key])"</span>)}</code><ul  ><li >1</li><li >2</li><li >3</li><li >4</li></ul>

也可以遍历所有的值:

 字典值或者键转换成数组 

如果不清楚Array有这么一个构造函数,那么您可能会手动写代码去遍历,但是事实上我们可以直接使用构造函数来实现的。我们知道字典的keys和values属性返回来的是LazyMapCollection<key,value>类型,并不是我们直接需要到的数据,因此我们有的时候需要转换成我们直接能使用的数据,这时候就需要这么做的:

          总结       

以上是内存溢出为你收集整理的Swift 数组、字典和集合全部内容,希望文章能够帮你解决Swift 数组、字典和集合所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1070901.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存