集合

175 阅读7分钟

不同的结构对应于不同的算法,有的考虑节省占用空间,有的考虑提高运行速度,对于程序员而言,它们就像是“熊掌”和“鱼肉”,不可兼得!提高运行速度往往是以牺牲空间为代价的,而节省占用空间往往是以牺牲运行速度为代价的。

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"

数组复制

与字典的复制类似,在为数组赋值或参数传递的时候,数组总是发生复制行为。而数组中的数据是否也发生复制行为,要看数据本身的类型。