Swift入门(五)——数组(Array)

集合

集合的定义

Swift中提供了两种数据结构用于存放数据的集合,分别是数组(Array)和字典(Dictionary)。他们的主要区别在于数组中的元素由下标确定,而字典中的数据的值由数据的键(Key)决定。以下我们认为集合就是数组或字典。

集合的可变性

我们可以定义一个集合常量或者集合变量。一旦定义为常量,就意味着集合的长度、内容和顺序都不能再修改了。比如,定义为常量的数组,不能再向其中添加新的元素。

数组的创建

由于swift中变量的创建遵循“ var 变量名:变量类型 ”的语法,因此数组的创建归根结底还是数组类型的定义。一共有三种方法来定义数组的类型:

var arrayOne:Array<Int> = [1,2,3]
println("arrayLong = \(arrayOne)")

var arrayTwo:[Int] = [1,2,3]
println("arrayShort = \(arrayTwo)")

var arrayThree = [1,2,3]
println("arrayThree = \(arrayThree)")

第一种是数组类型的完整定义,即Array关键字加上一对尖括号,括号内写上数组元素的类型。

第二种是数组类型的简化定义,即一对方括号内写上数组元素的类型。这与第一种定义方法完全等价。

在使用这两种方法定义数组的时候,一定要确保数组中每个元素类型相同,否则将会产生编译错误。

第三种运用了Swift的类型推导的特性。需要注意的是,数组的值由方括号组成,里面的元素用逗号隔开。如果方括号改成了圆括号,编译器不会报错(这将变成元组),所以千万要小心,避免莫名其妙的错误。

第三种方法除了书写简单之外,还有一种好处,即不必确保数组中每个元素类型相同。我们来通过代码看一看多个不同类型的元素出现在统一数组中会发生什么情况:

var arrayThree = [1,2,3]
println("arrayThree = \(arrayThree)")

var arrayMixed = [1,"abc",true, 1.5]
println("arrayMixed = \(arrayMixed)")//在这一行结束前设置断点
//在LLDB调试其中分别输入print arrayThree和print arrayMixed

可以得到如下结果

([Int]) $R0 = 3 values {
  [0] = 1
  [1] = 2
  [2] = 3
}

([NSObject]) $R1 = 4 values {
  [0] = 0x0000000000000137 Int64(1)
  [1] = "abc"
  [2] = 0x00007fff7255e8a8 {
    NSNumber = {
      NSValue = (null)
    }
  }
  [3] = 0x00000001006008a0 {
    NSNumber = {
      NSValue = (null)
    }
  }
}

因此不难发现,arrayMixed数组之所以可以添加多个类型的元素,是因为它被推导为Array< NSObject>类型。同样的,所以一旦数组的类型确定,就不能再插入不属于这个类型的的值。

在我阅读的教材上,作者特别提出,不指定类型的数组不能使用Array的append方法。但是经过我的测试,并没有这样的限制。有兴趣的读者可以自行测试,欢迎指正。

数组的访问与修改

数组长度

可以使用数组的只读属性count来获取数组长度:

var arrayThree = [1,2,3]
println("arrayThree.count = \(arrayThree.count)")

判断数组为空

可以使用数组的只读属性isEmpty来判断数组是否为空,当然通过判断count是否为0也可以达到同样的效果,不过代码略长一些。

var arrayThree = [1,2,3]
if !arrayThree.isEmpty{
    println("Array Three is not empty")
}

添加新元素

一共有两种方法可以在数组的尾部添加新元素:

//方法一,使用数组的append函数
var arrayThree = [1,2,3]
arrayThree.append(4)
println("arrayThree = \(arrayThree)")

//方法二,使用加法运算符
var arrayThree = [1,2,3]
arrayThree += [4]
println("arrayThree = \(arrayThree)")

无论使用哪种方法,都必须保证新添加的元素和数组类型相同。比如试图像arrayThree中添加元素’1.5’会导致编译错误。

可以看到,第二种方法的本质实际上是在两个数组对象之间调用加法运算符,得到的结果是两个数组拼接之后的结果。因此,第二种方法具有一个强大的功能,即向数组尾部添加多个元素。

还有一种通用的方法,即调用数组的insert(atIndex:)方法,在指定位置插入新元素。

var arrayThree = [1,2,3]
arrayThree.insert(4, atIndex: 2)
println("arrayThree = \(arrayThree)")

删除数组元素

可以调用数组的removeAtIndex()和removeLast()方法。

var arrayThree = [1,2,3]
var numberThree = arrayThree.removeAtIndex(2)
var numberTwo = arrayThree.removeLast()

这两个方法会返回被删除的元素的值,当然如果不需要知道,可以无视它的返回值,直接调用方法即可。

需要注意的一点是,removeAtIndex方法首先要判断下标是否越界,也就是说它会用到数组的长度。这意味着需要线性遍历数组,因此如果只需要移除数组的最后一个元素且数组长度很大时,应该使用removeLast()方法。

访问数组元素

了解了如何添加和删除元素,我们就要想办法把新加入的元素取出来看看了。通过数组下标可以访问指定位置的数组元素,语法与C语言相同。

var arrayThree = [1,2,3]
println("ArrayThree[2] = \(arrayThree[2])")

修改数组元素

下标不仅可以访问数组元素,还可以实现数组元素的修改。这和访问数组元素是非常类似的,只要交换等号两边变量的位置即可。

var arrayThree = [1,2,3]
var secondInt = arrayThree[1] //访问元素

var newSecond = 4
arrayThree[2] = newSecond //修改数组元素

不仅如此,还可以通过数组下标批量修改元素:

var arrayThree = [1,2,3]
var firstNumber = 1
var secondNumber = 2
arrayThree[0...1] = [firstNumber,secondNumber]

此时,等号的右侧必须是数组的字面量,而不能是一个数组变量。也就是说这样的写法是错误的:

var arrayThree = [1,2,3]
var newArray = [3,4]
var newSlice: ArraySlice<Int> = [3,4]
arrayThree[0...1] = newArray //错误。
arrayThree[0...1] = newSlice //正确

原因是左边的arrayThree[0…1]其实是一个SubArray,在Swift中它的类型叫做ArraySlice,即Int类型的数组切片,而右边是一个Array类型变量,根据Swift类型安全的特性,这样的操作自然是被禁止的。

如果左边的切片长度和右边的变量长度不一致会发生什么情况呢?不用过于担心,这不会产生任何错误。Swift会机智的帮我们解决这个问题。

var arrayOne:[Int] = [1,2,3]
var arrayTwo = [1,2,3]
var sliceOne:ArraySlice<Int> = [1,2,3]
var sliceTwo:ArraySlice<Int> = [1]
arrayOne[1...2] = sliceOne
arrayTwo[1...2] = sliceTwo
println("arrayOne = \(arrayOne)")
println("arrayTwo = \(arrayTwo)")

输出结果分别是:

arrayOne = [1, 1, 2, 3]
arrayTwo = [1, 1]

因此,如果变量长度超过切片长度,将会自动在切片位置后添加元素(如同arrayOne),相当于调用了数组的insert(atIndex:)方法若干次。同样地,如果变量长度少于切片长度,没有值的位置的元素自动被移除,后面的元素自动向前补上。相当于调用了数组的removeAtIndex()方法若干次。

虽然这样不会出现任何错误,不过出于逻辑严谨性考虑,应该避免等号两端变量长度不一样的情况。

数组遍历

之前我们介绍了数组的增删改操作,还缺少一个查找。也就是数组的遍历。在Swift中,除了像C语言那样定义一个下标变量,在for循环中遍历数组,还有两种方式遍历数组。

//方法一,使用for in循环快速遍历
var array = [1,2,3,2,1,32,99]
for number in array{
    println("number = \(number)")
}

通过观察输出结果可以发现,for in循环是按照从前向后的顺序遍历数组的。

//方法二:使用enumerate函数
var array = [1,2,3,2,1,32,99]
for (index, value) in enumerate(array){
    println("value = \(value)")
}

enumerate(array)方法的返回值是一个数组。数组中的每一个元素都是一个二元元组。第一个值是下标index,第二个值是元素的值。这种方法也是顺序遍历数组。

数组的初始化

在本章的开头,我们利用数组字面量来初始化一个数组。其实,数组还有其他的初始化方法。

首先类比字符串的构造方法var string = String(),我们可以得知数组的另外两种构造方法。

var arrayOne = [Int]()
var arrayTwo = Array<Int>()
println("第一个数组元素个数为:\(arrayOne.count)")
println("第二个数组元素个数为:\(arrayTwo.count)")

运行结果:

第一个数组元素个数为:0
第二个数组元素个数为:0

除此以外,数组还有一种特殊的构造方法,可以指定数组长度,在这种情况下还必须强制指定数组中每个元素的值。如果觉得没用的话,可以先设置为0,然后再修改。

var arrayThree = [Int](count: 5, repeatedValue: 0)
var arrayFour = Array<Int>(count: 5, repeatedValue: 0)
var arrayFiver = Array(count: 5, repeatedValue: 0)
print("第三个数组为:\(arrayThree)")
print("第四个数组为:\(arrayFour)")
print("第五个数组为:\(arrayFiver)")

得益于类型推导,第五种数组初始化方法也是合法的。但是之前的标准初始化方法不可以这么简化。输出结果如下:

第三个数组为:[0, 0, 0, 0, 0]
第四个数组为:[1, 1, 1, 1, 1]
第五个数组为:[2, 2, 2, 2, 2]

附录

查看完整专栏——《Swift轻松入门》

【Swift入门(一)——基本语法】

【Swift入门(二)——字符与字符串】

【Swift入门(三)——元组(Tuple)】

【Swift入门(四)——可选类型(Optionals)与断言(Assert)】

【Swift入门(五)——数组(Array)】

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-07 17:02:39

Swift入门(五)——数组(Array)的相关文章

学习Swift -- 数组(Array) - 持续更新

集合类型--数组 Array是Swift中的一种集合类型:数组,数组是使用有序列表储存同一类型的多个值,与OC的NSArray的最大不同是,Swift的数组是值类型,OC的数组是引用类型 声明数组的方法 // 如果声明可变数组 就设置为变量 var someMutableArray = [Int]() // 声明了空数组 类型为Int // 相反声明不可变数组就设置为常量 let someArray = Array(count: 5, repeatedValue: 0.03) // 声明了一个不

swift基本用法-数组array

数组简单用法 //------------------------------------------------------------------------------ // 1. 数组定义 // 1> 使用[]可以快速定义数组,每一个数组元素使用 , 分隔 // 2> 数组中的数据元素可以是不同类型 var array = ["hello", "swift", 1, 1.2] //---------------------------------

Swift入门(九)——String与Int、Double、Float等数字相互转换

三种转换模式 任何语言里面,Int.float.double等数字类型自成一派,但它们和String类型之间的转换总是不太方便,这里总结一下它们相互转换的方法.总结下来一共有三种转换模式,分别举例说明. 一.String转数字 这里以String类型转Int类型为例.String转其他的数字类型(Float.Double等)大同小异.主要用到的方法是String类型的toInt方法.注意这个方法返回的是Int?,即一个整数可选类型.所以需要解封. var string = "1234"

Swift入门(十二)——利用Extension添加逆序输出字符串方法

Swift好像没有自带逆序输出字符串的方法,于是决定通过拓展(Extension)给String类添加一个逆序输出字符串的reverse方法. 首先新建一个Swift文件,命名规则不太清楚,于是暂且模仿OC叫做String+Operation吧,然后实现我们需要拓展的方法.下面先贴上代码,然后解释一下这段代码. //String+Operation.swifft import Foundation //逆序输出swift中的字符串 extension String{ func Reverse()

Swift入门(十一)——类型转换与is、as操作

三种操作:is.as?和as! Swift是强类型语言,但也允许开发者通过is.as?和as!这三种操作来对类型进行判断和强制转换.其中is用作类型判断,而as?和as!则分别是类型转换的可选形式和强制形式.在这里强调一下,swift中比较常用的向下转换(downcast)是没有as操作符的. 为了方便后面的解释,这里假设定义了三个类,Fruit.Apple和Orange,其中Apple和Orange都继承自Fruit. is操作符 is操作用来判断某一个对象是否是某一个特定的类,它会返回一个b

Swift入门(一)——基本的语法

近期開始学习swift.把学习的过程和总结整理成一个系列.方便日后回想总结. 基本的语法 基础语法 swift中每一行结束后不须要加分号.多个语句在同一行内须要用分好隔开 //表示凝视.或者用/* --*/ 常量 常量是指定义之后无法改动值的量,比方设置一个最大尝试登陆的次数,它的值一旦被确定,就不应该在程序中被改动.swift中的常量用let表示.定义方法例如以下: let maxAttemptTime = 3 //正确 maxAttemptTime = 4 //错误.常量一旦定义不能够改变

Swift入门(六)——字典(Dictionary)

字典的定义 和上一篇文章讲到的数组类似,字典也是用来存放相同数据类型的元素的数据结构.不过字典是通过键(Key)来查找特定的值(Value),字典中存放的每一个数据项(item)都是这样的一个键值对. 哈希化 每一个键值对的值,没有特殊要求,但是只有可以哈希化的类型的变量,才可以作为键值对的键.可以哈希化是指,该类型的变量,必须提供一个可以计算出自身哈希值的方法.哈希值不相同的变量,自身一定也不相同,反之则不一定成立. 在判断a == b的时候,其实会转化为a.hashValue == b.ha

IOS开发语言Swift入门连载---控制流

IOS开发语言Swift入门连载-控制流 Swift提供了类似 C 语言的流程控制结构,包括可以多次执行任务的for 和while 循环,基于特定条件选择执行不同代码分支的if 和switch 语句,还有控制流程跳转到其他代码的break 和continue 语句. 除了 C 语言里面传统的 for 条件递增(for-condition-increment )循环,Swift 还增加了for-in 循环,用来更简单地遍历数组(array),字典(dictionary),区间(range),字符串

IOS开发语言Swift入门连载---类和结构体

IOS开发语言Swift入门连载-类和结构体 类和结构体是人们构建代码所用的一种通用且灵活的构造体.为了在类和结构体中实现各种功能,我们必须要严格按照常量.变量以及函数所规定的语法规则来定义属性和添加方法. 与其他编程语言所不同的是,Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件.你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口. 注意: 通常一个类 的实例被称为对象 .然而在Swift 中,类和结构体的关系要比在其他语言中更加的密切,本