集合类型

上一篇:控制流
当前篇:集合类型
下一篇:基础大杂烩

这一课我们将学习更加抽象的数据类型:集合类型 ,集合类型是用来存在某个特定类型实例的集合,就像鞋柜,它有很多格子,专门用来装鞋,我们打开几号格子的门就能取出其中的鞋子,当然生活中我们可以在鞋柜中放什么都行,代码中不行,集合中只能放指定类型的实例

Swift 为我们提供了 ArraySetDictionary 三种集合类型,Array 被称为数组,它按先后顺序存放一组数据;Set 被称为集合 ,它没有顺序,但是也没有重复数据,也就是说一个集合中只可能有一个 1 ;Dictionary 被称为字典,它是一个无序的键值对的数据集,也就是一个键对应一个值,就像我们用英文字典查某个单词,一定是在首字母对应的区域去找,这里的首字母就是键 key ,这个单词就是值 value

集合类型有 可变不可变 之分,还记得前面学过的常量 let 和变量 var 吗,常量集合类型就是不可变集合,一旦赋值就不可更改,变量集合类型就是可变集合 ,只有可变集合才允许往其中添加或删除数据

数组(Array)

我们先来创建一个空的用于存放整数的数组:

var numbers = Array.init()

Array 表示数组类型,<>表示指定数组中存放数据的类型,我们指定的是 Int 类型,init() 是初始化(initialize)的意思,这句话的意思是:创建一个存放整数类型的数组,并赋给变量 numbers

我首先把最难看也是最完整的创建数组的方式展示出来,一是先苦后甜,二是展示Swift的语法糖,后面我们将一步一步的缩略这一行创建数组的代码

任何类型都有初始化方法,使用初始化方法才能创建出一个实例,初始化方法 init() 可以省略成 () :

var numbers = Array()

Array 类型可以用简化方式 [Int] 表示,所以代码最简方式如下:

var numbers = [Int]()

记住这种创建数组的方式,因为这是我们用的最多的方式,一切从简,为了全面理解实例的创建方式,下面我贴出一些代码供参考:

var numbers: Array = []
var numbers: [Int] = []
var letters = [String]()    //这是一个字符串数组

使用字面量创建数组:

let a = Int.init(1)

上面这句话跟 let a = 1 是一个意思,只不过我们平常不这样写,太麻烦,像 let a = 1 这样的创建方式叫做字面量,可以理解为键盘能敲出来的东西,数组同样可以用字面量来创建:

let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let fruits = ["Apple", "Banana", "Pear", "", ""]

还记得自动类型推断吗,numbers 自动推断为 [Int] ,fruits 自动推断为 [String],使用字面量创建数组时不要使用不同的类型,虽然数组中可以存放不同类型的数据,但是本节课不学习这个知识点

相同类型的数组可以使用 + 运算来合成新的数组:

let yourSnacks = ["Cookies", "Potato chips", "Sugar", "Chocolate", "LaTiao", "ShaQiMa"]
let mySnacks = ["FangBianMian"]
let ourSnacks = yourSnacks + mySnacks

添加修改数据

我们可以向可变数组中添加和插入数据

var numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.append(9)   //在数组最后添加整数 9
print(numbers)
numbers.insert(0, at: 0)    //在数组的第 0 个位置插入整数 0
print(numbers)
let number = numbers[2]    //访问第3个位置上的元素
print(number)   // 2
numbers[2] = -1    //将第三个位置上的元素替换为 -1

append 和 insert 是数组本身的功能函数,调用函数使用 . 加函数名加函数参数,函数的知识后续课程会详细学习,访问数组中某个位置的元素使用 [位置下标]

数组越界:insert 以及通过下标访问数组会存在数组越界的风险,也就是说,如果数组总共只有10个数据,我们要是在第100的位置上插入数据或者访问第100位置上的元素,都会造成程序崩溃,所以当我们在不确定是否会越界的时候,为了程序的稳定性,需要做一些判断:

var numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.append(9)
print(numbers)

let insertIndex = 0
if insertIndex >= 0 && insertIndex <= numbers.count {
    numbers.insert(0, at: insertIndex)
}
print(numbers)

let visitIndex = 2
if visitIndex >= 0 && visitIndex < numbers.count {
    let number = numbers[2]
    print(number)
    numbers[2] = -1
}

删除数据

可变数组中的数据也可以删除

var yourSnacks = ["Cookies", "Potato chips", "Sugar", "Chocolate", "LaTiao", "ShaQiMa"]
yourSnacks.removeFirst()    //删除第一个数据
yourSnacks.removeLast()     //删除最后一个数据
yourSnacks.remove(at: 1)    //删除下标为1,也就是第2个数据
yourSnacks.removeAll()      //删除所有数据
var yourSnacks = ["Cookies", "Potato chips", "Sugar", "Chocolate", "LaTiao", "ShaQiMa"]
yourSnacks.removeFirst(2)   //删除前两个数据
yourSnacks.removeLast(2)    //删除最后两个数据
//removeFirst 和 removeLast 有不同的用法,后面我们会学到,方法的多样化

遍历数组

var yourSnacks = ["Cookies", "Potato chips", "Sugar", "Chocolate", "LaTiao", "ShaQiMa"]

for snack in yourSnacks {
    print(snack)
}

for index in 0..

实际上数组还有很多很多的用法,我们先了解这些最基本的增删改查就够了,实际开发中需要的时候,我们再去了解更多的用法。Swift为我们提供的任何一个类型都会有很多很多的属性和方法,在学习的时候不需要一次性了解全部,可以一边开发一边了解

集合(Set)

Set 跟数组类似,但是特点不一样,Set 是无序的集合,也就是说不能通过下标位置来访问数组,Set 中没有重复数据,也就是说不管你在一个整数集合中插入多少个 1 ,其中只会有一个 1

下面我们来创建一个字符串集合,简写形式以及被数组占用了,所以集合就得老老实实写类型定义了,毕竟数组比集合更常用

var fruits = Set()
fruits.insert("Apple")
fruits.insert("Banana")
fruits.insert("Pear")
fruits.insert("Apple")  //集合里仍然只有一个唯一的苹果
fruits.remove("Apple")  //集合里有苹果,则把苹果删除
fruits.remove("Orange") //集合里并没有橘子,所以啥也没干
fruits.removeAll()      //清空集合中的数据

我们可以通过字面量创建一个集合,他的形式跟数组字面量是一样的,只不过我们需要声明一下集合类型,因为自动类型推断以及给了数组

let fruits: Set = ["Apple", "Banana", "Pear", "Orange", "Grape", "Apple"]
print(fruits)
//虽然我们在字面量里写了两个 Apple ,但是实际上创建完成后就只剩一个了

我们可以通过集合的长度,也就是其中的数据的数量,或者集合的 isEmpty 属性来判断集合是否是空的,我们可以用 contains 方法来判断集合中是否包含某个值

let fruits: Set = ["Apple", "Banana", "Pear", "Orange", "Grape", "Apple"]
if fruits.count == 0 {
    print("fruits set is empty")
}
if fruits.isEmpty {
    print("fruits set is empty")
}
if fruits.contains("Apple") {
    print("fruits set contains Apple")
}

集合也是可以遍历的,但是集合是无序的,所以我们只能用 for-in 语句来遍历,并且其中元素被访问的先后顺序也是不确定的

let fruits: Set = ["Apple", "Banana", "Pear", "Orange", "Grape", "Apple"]
for fruit in fruits {
    print(fruit)
}

集合还有一些方法,比如某个集合是否是另外一个集合的子集,是否包含在另一个集合中等等,跟数学里的集合是一个意思,实际上这些方法我至今也没用过,集合的作用主要用来避免重复数据以及判断包含关系

字典(Dictionary)

字典是一个键值对,一个键 key 对应一个值 value,字典中的元素同样没有顺序,我们需要通过 key 去访问对应的值。给字典指定数据类型的时候,我们需要分别指定 key 的类型和 value 的类型了,下面我们创建一个空的字典

var namesOfNumbers = Dictionary()
namesOfNumbers[0] = "zero"  //现在 0 对应的值就是 "zero"了

字典也有对应的简写形式,非常直观

var namesOfNumbers = [Int : String]()
namesOfNumbers[0] = "zero"  //现在 0 对应的值就是 "zero"了
namesOfNumbers[1] = "ome"   //现在 1 对应的值就是 "ome"了
namesOfNumbers[1] = "one"   //上面我们把"one"写成"ome"了,没关系,我们可以改回来
print(namesOfNumbers[1])

字典中的方括号不是指下标的意思,而是指 key ,下面我们用字符串来做 key

var numbersOfNames = [String : Int]()
numbersOfNames["zero"] = 0  //现在 "zero" 对应的值就是 0 了
numbersOfNames["one"] = 1   //现在 "one" 对应的值就是 1 了
numbersOfNames["two"] = 2   //现在 "two" 对应的值就是 2 了
print(numbersOfNames["two"])

我们也可以通过字面量来创建一个字典

var numbersOfNames = ["zero" : 0, "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5, "six" : 6, "nine" : 9]

冒号表示一个 key 对应一个 value ,冒号前面的是 key ,后面的是 value ,键值对之间用逗号隔开。这样一长串的字面量看起来很累,我们可以适当地运用换行来改善代码可读性

var numbersOfNames = ["zero" : 0,
                      "one" : 1,
                      "two" : 2,
                      "three" : 3,
                      "four" : 4,
                      "five" : 5,
                      "six" : 6,
                      "nine" : 9]

如果我们要删除某个 key 及其对应的值呢,可以用 removeValue(forKey:) 方法,清空字典用removeAll

var numbersOfNames = ["zero" : 0,
                      "one" : 1,
                      "two" : 2,
                      "three" : 3,
                      "four" : 4,
                      "five" : 5,
                      "six" : 6,
                      "nine" : 9]
numbersOfNames.removeValue(forKey: "five")
print(numbersOfNames)
numbersOfNames.removeAll()
if numbersOfNames.isEmpty {
    print("no numbers")
}

下面我通过字典来引出下一课的知识点

可选类型

设想一下,当我们通过某个 key 去获取对应的值的时候,可能会出现两种情况,一种是取到值了,另一种是字典里没有我们想要的东西,这个时候怎么办呢,请看下面代码

var numbersOfNames = ["zero" : 0,
                      "one" : 1,
                      "two" : 2,
                      "three" : 3,
                      "four" : 4,
                      "five" : 5,
                      "six" : 6,
                      "nine" : 9]
let eleven = numbersOfNames["eleven"]
print(eleven)

在黑框中我们没有看到输出任何的整数,而是输出了一个 nilnil 这个特殊符号在 Swift 中非常重要,它代表 ,代表 不存在 ,现在我们把代码稍微改一下

var numbersOfNames = ["zero" : 0,
                      "one" : 1,
                      "two" : 2,
                      "three" : 3,
                      "four" : 4,
                      "five" : 5,
                      "six" : 6,
                      "nine" : 9]
let eleven = numbersOfNames["eleven"]
if eleven == nil {
    print("There is no eleven")
} else {
    print(eleven)
}

更重要的是,我们可能会认为 eleven 会被自动推断为 Int 类型,那么我们再把代码修改一下

var numbersOfNames = ["zero" : 0,
                      "one" : 1,
                      "two" : 2,
                      "three" : 3,
                      "four" : 4,
                      "five" : 5,
                      "six" : 6,
                      "nine" : 9]
let eleven: Int = numbersOfNames["eleven"]
if eleven == nil {
    print("There is no eleven")
} else {
    print(eleven)
}

编译器报错:“Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?”,也就是说 numberOfNames["eleven"] 获取到的值的类型是 Int? ,而不是 Int ,他们虽然基本上是一个类型,但又不完全一样,唯一的区别就在于,Int? 类型表示 Int 的可选类型,可选类型就代表它的值可能是 nil ,也可能是一个整数,任何类型都可以在后面加一个?表示成可选类型,实际上,任何字典通过 key 获取的值永远都是对应类型的可选类型

可选类型不难理解,比如说我的 地点,按道理说,无论我在什么地方,都会有一个确定点,因此我的 地点 就不需要声明为可选类型,但是我的 女朋友 就可能是 nil 了,那就需要将这个类型声明为可选类型 女朋友? ,这个问号很形象,好像是在提醒你 “有吗?”

元组

第二个要引出的新知识点是 元组,我们在讲字典的时候没有将字典的遍历,因为字典的遍历引出了 元组 这个知识点,请输入下面的代码查看运行结果

var numbersOfNames = ["zero" : 0,
                      "one" : 1,
                      "two" : 2,
                      "three" : 3,
                      "four" : 4,
                      "five" : 5,
                      "six" : 6,
                      "nine" : 9]
for number in numbersOfNames {
    print(number)
}
//(key: "three", value: 3)
//(key: "one", value: 1)
//(key: "nine", value: 9)
//(key: "four", value: 4)
//(key: "five", value: 5)
//(key: "zero", value: 0)
//(key: "six", value: 6)
//(key: "two", value: 2)

输出结果貌似跟预期的不一样,因为 keyvalue 是一一对应的相关联的,遍历的时候如果只给出 value ,那么我们就无法知道这个 valuekey 是什么,因此需要将它们捆绑在一起,这就叫 元组 ,它把多个值组合成一个复合值,并且任何类型的值都可以往里放

我们可以通过名称或者下标来访问 元组 中的某个值

var numbersOfNames = ["zero" : 0,
                      "one" : 1,
                      "two" : 2,
                      "three" : 3,
                      "four" : 4,
                      "five" : 5,
                      "six" : 6,
                      "nine" : 9]
for number in numbersOfNames {
    print("number of \(number.key) is \(number.value)")
}
//number of three is 3
//number of one is 1
//number of nine is 9
//number of four is 4
//number of five is 5
//number of zero is 0
//number of six is 6
//number of two is 2

元组也可以通过顺序来访问其中的值

var numbersOfNames = ["zero" : 0,
                      "one" : 1,
                      "two" : 2,
                      "three" : 3,
                      "four" : 4,
                      "five" : 5,
                      "six" : 6,
                      "nine" : 9]
for number in numbersOfNames {
    print("number of \(number.0) is \(number.1)")
}
//number of three is 3
//number of one is 1
//number of nine is 9
//number of four is 4
//number of five is 5
//number of zero is 0
//number of six is 6
//number of two is 2

现在,Swift 为我们提供的基础类型基本上就快讲完了,基础的东西本来就很少,我们使用最多的就是整数类型,浮点数类型,字符串类型,布尔类型,集合类型,以及这些类型的可选类型,基础知识很枯燥无聊,但是也很重要,下一课我们将剩余的基础知识全部过一遍,无须全部记住,先形成一个概念,在进阶学习中一点一滴地巩固基础知识

上一篇:控制流
当前篇:集合类型
下一篇:基础大杂烩

你可能感兴趣的:(集合类型)