第4章:Swift语言基础(三)——集合类型的创建与操作

好,咱们继续往前走。上一章聊了字符串和元组,这一章我带你搞定Swift里最常用的三种集合类型:数组、字典和集合。说实话,这三样东西你以后写代码几乎天天见,躲都躲不掉。

4.1 数组(Array)的创建与操作

数组,说白了就是一组有序的数据集合。我刚开始学Swift时,觉得数组不就是个列表嘛,有啥好学的?后来才发现,里面的门道还真不少。

4.1.1 创建数组

Swift里创建数组的方式有好几种,我个人习惯用类型推断,代码看起来更清爽。

// 方式一:字面量创建(最常用)
var fruits = ["苹果", "香蕉", "橘子"]
var numbers = [1, 2, 3, 4, 5]

// 方式二:指定类型创建
var scores: [Int] = [98, 87, 76, 92]
var names: Array<String> = ["张三", "李四", "王五"]

// 方式三:创建空数组
var emptyArray1: [String] = []
var emptyArray2 = [String]()
var emptyArray3 = Array<String>()

// 方式四:创建重复元素的数组
var allZeros = [Int](repeating: 0, count: 5)  // [0, 0, 0, 0, 0]
var defaultNames = [String](repeating: "未命名", count: 3)  // ["未命名", "未命名", "未命名"]
我的小建议:创建空数组时,我推荐用 var emptyArray = [String]() 这种写法。为什么?因为一眼就能看出类型,而且写法简洁。我在项目中见过有人用 Array<String>(),虽然没错,但总觉得有点啰嗦。

4.1.2 数组的基本操作

数组的操作其实就那几样:增删改查。咱们一个一个来看。

var shoppingList = ["牛奶", "鸡蛋", "面包"]

// 获取元素个数
print(shoppingList.count)  // 3

// 检查是否为空
if shoppingList.isEmpty {
    print("购物车是空的")
}

// 访问元素(注意下标从0开始)
let firstItem = shoppingList[0]  // "牛奶"
let secondItem = shoppingList[1] // "鸡蛋"

// 修改元素
shoppingList[2] = "全麦面包"  // 把"面包"改成"全麦面包"

// 添加元素
shoppingList.append("黄油")        // 在末尾添加
shoppingList += ["果酱", "蜂蜜"]    // 添加多个元素
shoppingList.insert("奶酪", at: 1) // 在指定位置插入

// 删除元素
shoppingList.remove(at: 0)      // 删除第一个元素
shoppingList.removeLast()       // 删除最后一个
shoppingList.removeAll()        // 清空数组
注意:访问数组元素时,下标不能越界!我曾经在项目中犯过这个错——数组只有3个元素,我却去访问 array[5],结果程序直接崩溃了。嗯,那感觉就像走路踩到坑,摔得挺疼。所以访问前最好先检查 count

4.1.3 数组的常用方法

Swift的数组还有很多实用的方法,我挑几个常用的说说。

var numbers = [3, 1, 4, 1, 5, 9, 2, 6]

// 排序
numbers.sort()  // 原地排序,[1, 1, 2, 3, 4, 5, 6, 9]
let sortedNumbers = numbers.sorted()  // 返回新数组,原数组不变

// 判断是否包含
if numbers.contains(5) {
    print("数组里有5")
}

// 获取第一个/最后一个元素
let first = numbers.first  // Optional(1)
let last = numbers.last    // Optional(9)

// 获取最小/最大值
let minValue = numbers.min()  // Optional(1)
let maxValue = numbers.max()  // Optional(9)

// 随机打乱
let shuffled = numbers.shuffled()  // 每次结果不同

4.2 字典(Dictionary)的创建与操作

字典跟数组不一样,它存的是键值对。你想想看,就像查字典一样,通过拼音(键)找到对应的字(值)。

4.2.1 创建字典

// 方式一:字面量创建
var studentScores = ["张三": 95, "李四": 87, "王五": 92]
var capitals = ["中国": "北京", "美国": "华盛顿", "日本": "东京"]

// 方式二:指定类型创建
var ages: [String: Int] = ["小明": 18, "小红": 20]
var phoneBook: Dictionary<String, String> = ["张三": "13800138000"]

// 方式三:创建空字典
var emptyDict1: [String: Int] = [:]
var emptyDict2 = [String: Int]()
var emptyDict3 = Dictionary<String, Int>()
我的经验:字典的键必须是可哈希的(Hashable)。什么意思呢?简单说就是键要能唯一标识自己。字符串、整数、浮点数都可以做键,但数组不行。我之前试过用数组做键,编译器直接报错,那场面...有点尴尬。

4.2.2 字典的基本操作

var userInfo = ["name": "张三", "age": "25", "city": "北京"]

// 获取元素个数
print(userInfo.count)  // 3

// 访问元素(返回可选类型)
let name = userInfo["name"]     // Optional("张三")
let gender = userInfo["gender"] // nil(键不存在)

// 修改元素
userInfo["age"] = "26"          // 直接赋值修改
userInfo.updateValue("上海", forKey: "city")  // 另一种修改方式

// 添加新键值对
userInfo["job"] = "工程师"      // 键不存在时就是添加

// 删除元素
userInfo.removeValue(forKey: "age")  // 删除指定键
userInfo["city"] = nil               // 赋值为nil也会删除

// 获取所有键或值
let allKeys = Array(userInfo.keys)     // ["name", "job"]
let allValues = Array(userInfo.values) // ["张三", "工程师"]
避坑指南:字典访问返回的是可选类型!我曾经在项目里直接 let age = userInfo["age"] 然后拿去计算,结果忘了解包,编译器报错报得我头大。记住:字典取值一定要处理可选值,要么用可选绑定,要么给默认值。

4.3 集合(Set)的创建与操作

集合跟数组有点像,但它有几个特点:元素无序、不重复、查找速度快。你想想看,如果你要检查一个元素是否存在,集合比数组快得多。

4.3.1 创建集合

// 方式一:字面量创建(需要显式声明Set类型)
var favoriteColors: Set = ["红色", "蓝色", "绿色"]
var luckyNumbers: Set<Int> = [7, 13, 21, 7]  // 重复的7只会保留一个

// 方式二:从数组转换
let array = [1, 2, 3, 2, 1]
let numberSet = Set(array)  // {1, 2, 3},重复元素被去重

// 方式三:创建空集合
var emptySet1: Set<String> = []
var emptySet2 = Set<String>()
说个细节:创建集合时一定要显式声明 Set 类型,不然Swift会把它当成数组。我第一次写的时候就踩了这个坑,写了 var colors = ["红", "蓝"],结果发现是个数组,不是集合。嗯,从那以后我就记住了。

4.3.2 集合的基本操作

var fruits: Set = ["苹果", "香蕉", "橘子", "葡萄"]

// 添加元素
fruits.insert("西瓜")

// 删除元素
fruits.remove("香蕉")     // 删除指定元素
fruits.removeAll()       // 清空集合

// 检查是否包含
if fruits.contains("苹果") {
    print("有苹果")
}

// 集合运算(数学里的那些)
let setA: Set = [1, 2, 3, 4, 5]
let setB: Set = [3, 4, 5, 6, 7]

let union = setA.union(setB)           // 并集:{1,2,3,4,5,6,7}
let intersection = setA.intersection(setB)  // 交集:{3,4,5}
let difference = setA.subtracting(setB)     // 差集:{1,2}
let symmetricDiff = setA.symmetricDifference(setB)  // 对称差:{1,2,6,7}

4.4 集合的遍历

遍历,说白了就是把集合里的元素挨个拿出来看看。三种集合的遍历方式大同小异,我一起说说。

4.4.1 for-in 循环遍历

// 遍历数组
let fruits = ["苹果", "香蕉", "橘子"]
for fruit in fruits {
    print(fruit)
}

// 遍历字典
let scores = ["张三": 95, "李四": 87, "王五": 92]
for (name, score) in scores {
    print("\(name)得了\(score)分")
}

// 遍历集合
let colors: Set = ["红", "蓝", "绿"]
for color in colors {
    print(color)  // 注意:顺序不确定
}

4.4.2 带索引的遍历

// 数组:使用enumerated()
let names = ["张三", "李四", "王五"]
for (index, name) in names.enumerated() {
    print("第\(index + 1)个人是\(name)")
}

// 字典:可以遍历keys或values
let userInfo = ["name": "张三", "age": "25", "city": "北京"]
for key in userInfo.keys {
    print("键:\(key)")
}
for value in userInfo.values {
    print("值:\(value)")
}

4.4.3 高阶函数遍历

Swift还提供了一些更高级的遍历方式,我工作中经常用。

let numbers = [1, 2, 3, 4, 5, 6]

// forEach:类似for-in,但不能用break和continue
numbers.forEach { number in
    print(number)
}

// map:遍历并转换每个元素
let doubled = numbers.map { $0 * 2 }  // [2, 4, 6, 8, 10, 12]

// filter:过滤出符合条件的元素
let evens = numbers.filter { $0 % 2 == 0 }  // [2, 4, 6]

// reduce:将集合合并为一个值
let sum = numbers.reduce(0, +)  // 21

// 链式调用(我特别喜欢这么写)
let result = numbers
    .filter { $0 > 3 }
    .map { $0 * 10 }
    .reduce(0, +)  // 4*10 + 5*10 + 6*10 = 150
重点总结:
  • 数组:有序、可重复、下标访问
  • 字典:键值对、键唯一、值可重复
  • 集合:无序、不重复、查找快
  • 遍历方式:for-in、enumerated()、高阶函数

好了,这一章的内容就到这儿。数组、字典、集合这三个家伙,你得多练练手。我刚开始学的时候,也是写了好多小demo才熟练的。下一章咱们聊聊控制流,if、switch、循环这些,到时候见。