不同的结构对应于不同的算法,有的考虑节省占用空间,有的考虑提高运行速度,对于程序员而言,它们就像是“熊掌”和“鱼肉”,不可兼得!提高运行速度往往是以牺牲空间为代价的,而节省占用空间往往是以牺牲运行速度为代价的。
Swift中提供了两种数据结构的实现:数组和字典。字典也叫映射或哈希表。这两种结构很有代表性,所以Swift主要提供了这两种结构的实现。
数组集合
数组是一串有序的由相同类型元素构成的集合。数组中的集合元素是有序的,可以重复出现。
提示:数组更关心元素是否有序,而对于是否重复则不关心,记住这个原则。
数组声明与初始化
Swift为数组提供Array结构体类型,在声明一个数组的时候可以使用下面的语句之一。
- var studentList1: Array
- var studentList2: [String]
其中变量studentList1明确指出类型为Array, 是泛型,说明在这个数组中只能存放字符串类型的数据。studentList2变量也是声明一个只能存放字符串类型的数组。[String]与Array是等价的,[String]是简化写法。
上面声明的集合事实上还不能用,还需要进行初始化,集合类型往往在声明的同事进行初始化。
- var studentList1: Array = ["张三", "李四", "王五", "董六"]
- var studentList2:[String] = ["张三", "李四", "王五", "董六"]
- let studentList3:[String] = ["张三", "李四", "王五", "董六"]
- var studentList4 = String//这个进行了初始化,只是没有元素 let声明的数组是不可变数组,必须在声明的同时进行初始化,一旦被初始化,就不可以被修改。不可变数组在访问效率上比可变数组(var声明的数组)要高,可变数组通过牺牲访问效率换取可变。
数组的修改
可以对数组中的元素进行追加、插入、删除和替换等修改操作。追加元素可以使用数组append方法或+操作符实现,插入元素可以使用数组的insert方法实现,删除元素可以使用数组的removeAtIndex方法实现。
print("--数组的修改---")
var studentList:[String] = ["张三", "李四", "王五"]
print(studentList)
studentList.append("董六")
print(studentList)
studentList += ["刘备", "关羽"]
studentList.insert("张飞", atIndex: studentList.count)
print(studentList)
let removeStudent = studentList.removeAtIndex(0)
print(studentList)
studentList[0] = "诸葛亮"
print(studentList)
数组遍历
数组最常用的操作是遍历集合,就是将数组中的每一个元素取出来,进行操作或计算。整个遍历过程与循环分不开,我们可以使用for in循环进行遍历。
print("--数组遍历---")
var studentList_:[String] = ["张三", "李四", "王五"]
for item in studentList_ {
print(item)
}
for (index, value) in studentList_.enumerate() {
print("Item \(index + 1) : \(value)")
}
第二个遍历方式适合于需要循环变量的情况,enumerate函数可以取出数组的索引和元素,其中(index, value)是元组类型。
字典集合
字典表示一种非常复杂的集合,允许按照某个键来访问元素。字典是由两部分集合构成的,一个是键(key)集合,一个是值(value)集合。键集合是不能有重复元素的,而值集合是可以重复的,键和值是成对出现的。
提示:字典中键和值得集合是无序的,即便在添加的时候是按照顺序添加的,当取出这些键或值的时候,也会变得无序。字典集合更适合通过键快速访问值,就像查英文字典一样,键就是要查的英文单词,而值是英文单词的翻译和解释等。有的时候,一个英文单词会对应多个翻译和解释,这也是与字典集合特性对应的。
字典声明与初始化
Swift为字典提供了Dictionary结构体类型,我们在声明一个字典的时候可以使用下面的语句。
- var studentDictionary:Dictionary<Int, String>
其中,变量studentDictionary明确指定类型为Dictionary<Int, String>。其中<Int, String>是泛型,这表明键的集合是Int类型,值的集合是String类型。
上面声明的集合事实上还不能用,还需要进行初始化,集合类型往往是声明的同时进行初始化的。
- var studentDictionary1:Dictionary<Int, String> = [102:"张三"]
- var studentDictionary2 = [102: "张三", 105:"李四", 109:"王五"]
- let studentDictionary3 = [102: "张三", 105:"李四", 109:"王五"]
- var studentDictionary4 = Dictionary<Int, String>()
字典的修改
可以对字典中的元素进行追加、删除和替换等修改操作。字典元素的追加比较简单,只要给一个不存在的键赋一个有效值,就会追加一个"键-值"对元素。
字典元素删除有两种方法,一种是给一个键赋值为nil,就可以删除元素;另一种方法是通过字典的removeValueForKey方法删除元素,方法返回值是要删除的值。
字典元素替换也有两种方法,一种是直接给一个存在的键赋值,这样新值就会替换旧值;另一种方法是通过updateValue(forKey:)方法替换,方法的返回值是要替换的值。
print("---字典的修改----")
var studentDictionary = [102 : "张三", 105 : "李四", 109 : "王五"]
studentDictionary[110] = "董六"
print("班级人数: \(studentDictionary.count)")
let dismissStudent = studentDictionary.removeValueForKey(102)
print("开除的学生: \(dismissStudent)")
print(studentDictionary)
studentDictionary[105] = nil
print(studentDictionary)
studentDictionary[109] = "张三"
print(studentDictionary)
let replaceStudent = studentDictionary.updateValue("李四", forKey: 110)
print("被替换的学生是:\(replaceStudent)")
print(studentDictionary)
字典遍历
字典遍历集合也是字典的重要操作。与数组不同,字典有两个集合,因此遍历过程可以只遍历值的集合,也可以只遍历键的集合,也可以同时遍历。这些遍历过程都是通过for in循环实现的。
print("--字典遍历--")
var studentDictionary__ = [102 : "张三", 105 : "李四", 109 : "王五"]
print("--遍历键--")
for studentID in studentDictionary__.keys {
print("学号: \(studentID)")
}
print("--遍历值--")
for studentName in studentDictionary__.values {
print("学生: \(studentName)")
}
print("--遍历键:值---")
for (studentID, studentName) in studentDictionary__ {
print("\(studentID) : \(studentName)")
}
其中keys是字典属性,可以返回所有键的集合。values是字典属性,可以返回所有值得集合。
集合的复制
集合在赋值或参数传递过程中会发生复制。Swift中的集合都是结构体类型,即值类型。值类型在赋值或参数传递时会发生复制行为,赋予的值或传递的参数是一个副本;而引用类型在赋值或参数传递时不发生复制行为,赋予的值或传递的参数是一个引用(实例本身)。
同样是值类型,集合要比其他值类型(整型、浮点型等)的复制行为更复杂,这是因为集合里面包含了一些数据。这些数据是否发生复制行为,要看这些数据本身是值类型还是引用类型,如果是值类型则发生复制行为,如果是引用类型则不发生复制行为。
字典复制
在为字典赋值或参数传递的时候,字典总是发生复制行为。而字典中的键和值等数据是否发生复制,要看本身键和值本身的类型。
print("--字典复制--值类型--")
var students = [102 : "张三",105 : "李四"]
var copyStudents = students
copyStudents[102] = "王五"
print(students[102])
print("--字典复制--引用类型--")
class Employee {
var name : String // 姓名
var salary : Double // 工资
init (n : String) {
name = n
salary = 0
}
}
var emps = Dictionary<String, Employee>()
let emp1 = Employee(n: "Amy Lee")
let emp2 = Employee(n: "Harry Hacker")
emps["144-25-5464"] = emp1
emps["567-24-2546"] = emp2
//赋值,发生拷贝
var copyEmps = emps
let copyEmp : Employee! = copyEmps["567-24-2546"]
copyEmp.name = "Gary Cooper"
let emp : Employee! = emps["567-24-2546"]
print(emp.name)
由于字典中存放的键和值都是值类型,也发生了复制行为,所以修改copyStudents[102]内容的时候,不会影响students[102]内容,输出的还是“张三”
将字典变量emps赋值给copyEmps变量,这个过程中发生了复制行为,但是由于emp1和emp2对象是引用类型,不发生复制,因此修改copyEmp内容之后,打印的时候输出"Gary Cooper"
数组复制
与字典的复制类似,在为数组赋值或参数传递的时候,数组总是发生复制行为。而数组中的数据是否也发生复制行为,要看数据本身的类型。