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)】
【Swift入门(六)——字典(Dictionary)】
【Swift入门(七)——结构体(Struct)】
【Swift入门(八)——功能强大的求余运算符】
【Swift入门(九)——String与Int、Double、Float等数字相互转换】
【Swift入门(十)——循环引用、弱引用和无主引用】
【Swift入门(十一)——类型转换与is、as操作】
【Swift入门(十二)——利用Extension加入逆序输出字符串方法】

原文地址:https://www.cnblogs.com/zsychanpin/p/7106636.html