数据结构 — 字典(Dict)

字典(Dict)

在 Swift 中,Dictionary 是一组 键值对 的集合,提供了许多接口(方法和属性)来管理和操作字典。Dictionary 的键是唯一的,值可以是任意类型,甚至可以重复。以下是 Dictionary 的常用接口,按功能分类列表并附中文说明及示例。


1. 字典基本信息 #

属性或方法功能说明示例
count返回字典中键值对的数量。print(dict.count)
isEmpty检查字典是否为空,空返回 trueif dict.isEmpty { print("Empty dictionary") }
keys返回字典中所有键的集合(类型为 Dictionary.Keys)。let allKeys = dict.keys
values返回字典中所有值的集合(类型为 Dictionary.Values)。let allValues = dict.values

2. 添加和更新 #

方法名称功能说明示例
updateValue(_:forKey:)更新指定键的值,如果键不存在则添加,返回原来的值(可选类型)。let oldValue = dict.updateValue(30, forKey: "age")
subscript(_:)通过键访问或设置字典的值,如果键不存在则添加新键值。dict["name"] = "Alice"; let value = dict["name"]

3. 删除 #

方法名称功能说明示例
removeValue(forKey:)删除指定键对应的值,返回被删除的值(如果不存在,返回 nil)。let removedValue = dict.removeValue(forKey: "age")
removeAll()删除字典中所有键值对,字典变为空。dict.removeAll()

4. 查询操作 #

方法名称功能说明示例
contains(where:)检查字典中是否有键值对满足指定条件。let exist = dict.contains(where: { $0.key == "name" })
first(where:)返回第一个满足条件的键值对(可选类型)。let result = dict.first(where: { $0.value == "Alice" })
keys.contains(_:)检查字典是否包含指定键。if dict.keys.contains("name") { print("Key exists") }

5. 合并 #

方法名称功能说明示例
merging(_:uniquingKeysWith:)合并两个字典,指定冲突时的键值处理逻辑,返回新字典。let result = dict.merging(newDict) { old, new in new }
merge(_:uniquingKeysWith:)原地合并两个字典,指定冲突时的键值处理逻辑。dict.merge(newDict) { (_, new) in new }

6. 遍历 #

方法名称功能说明示例
forEach(_:)遍历字典中的所有键值对,执行闭包中的操作。dict.forEach { print("\($0.key): \($0.value)") }
map(_:)对每个键值对进行映射,返回包含转换结果的新数组。let result = dict.map { $0.key + ":" + "\($0.value)" }
filter(_:)筛选满足条件的键值对,返回新的字典。let filtered = dict.filter { $0.value as? Int ?? 0 > 20 }

7. 数据提取与变换 #

方法名称功能说明示例
compactMapValues(_:)对字典值进行映射,并移除返回 nil 的键值对。let newDict = dict.compactMapValues { Int($0) }
mapValues(_:)对字典的每个值进行映射,返回修改后的新字典。let modified = dict.mapValues { "\($0)!" }
reduce(_:_:)将字典中的所有键值对组合计算成一个值。let result = dict.reduce(0) { $0 + ($1.value as? Int ?? 0) }

8. 默认值访问(防止键不存在问题) #

方法名称功能说明示例
subscript(_:default:)如果键存在则返回对应值,否则返回指定的默认值。let value = dict["name", default: "No Name"]

9. 字典操作(创建、更新、合并) #

创建字典 #

方法功能说明示例
使用字典字面量使用简单的键值对字面量创建字典。let dict: [String: Int] = ["age": 25, "score": 100]
使用 init(uniqueKeysWithValues:)使用键值对数组自动生成字典,键不能重复。let dict = Dictionary(uniqueKeysWithValues: [("key1", "value1"), ("key2", "value2")])

字典合并 #

用法功能说明示例
合并字典合并多个字典,冲突时指定处理逻辑。let result = dict1.merging(dict2, uniquingKeysWith: { oldValue, newValue in newValue })

10. Swift 5.7+ 特性 #

新增方法功能说明示例
grouping(_:by:)根据指定的分组规则,将数组转化为字典,以指定条件分组键值。let grouped = Dictionary(grouping: [1, 2, 3, 4, 5], by: { $0 % 2 })
Dictionary(_:uniquingKeysWith:)通过键值对直接生成字典,冲突时指定处理逻辑。let dict = Dictionary([("a", 1), ("b", 2)], uniquingKeysWith: max)

11. 类型检查和比较 #

方法名称功能说明示例
==比较两个字典内容是否完全相同(键值对一一匹配)。if dict1 == dict2 { print("Equal") }
keys.sorted()按键排序并返回排序后的键集合。let sortedKeys = dict.keys.sorted()

基础获取方法 #

1. 使用下标语法(最常用) #

let capitals = ["France": "Paris", "Italy": "Rome", "Japan": "Tokyo"]

// 获取值(返回可选类型)
if let paris = capitals["France"] {
    print("法国的首都是 \(paris)") // 输出: 法国的首都是 Paris
}

// 获取不存在的键
let london = capitals["UK"] // london 为 nil

2. 使用 subscript(_:default:) 方法(Swift 4+) #

// 提供默认值
let ukCapital = capitals["UK", default: "London"]
print(ukCapital) // 输出: London

// 计算出现次数
let words = ["apple", "banana", "apple", "orange"]
var wordCounts = [String: Int]()
for word in words {
    wordCounts[word, default: 0] += 1
}
print(wordCounts) // 输出: ["apple": 2, "banana": 1, "orange": 1]

高级获取方法 #

3. 使用 first(where:) 方法 #

// 查找第一个符合条件的键值对
if let firstCapital = capitals.first(where: { $0.key == "Italy" }) {
    print("意大利的首都是 \(firstCapital.value)") // 输出: 意大利的首都是 Rome
}

4. 使用 keys 和 values 属性 #

// 获取所有键
let countries = capitals.keys
print(countries) // 输出: ["France", "Italy", "Japan"]

// 获取所有值
let cities = capitals.values
print(cities) // 输出: ["Paris", "Rome", "Tokyo"]

5. 使用 filter 方法 #

// 过滤符合条件的键值对
let asianCountries = capitals.filter { country, capital in
    country == "Japan" || country == "China"
}
print(asianCountries) // 输出: ["Japan": "Tokyo"]

安全获取模式 #

6. 可选绑定(推荐) #

if let italyCapital = capitals["Italy"] {
    print("意大利的首都是 \(italyCapital)")
} else {
    print("未找到意大利的首都信息")
}

7. 空合运算符(Nil-Coalescing Operator) #

let germanyCapital = capitals["Germany"] ?? "Berlin"
print(germanyCapital) // 输出: Berlin

8. 使用 guard let 语句 #

func printCapital(for country: String) {
    guard let capital = capitals[country] else {
        print("未找到 \(country) 的首都信息")
        return
    }
    print("\(country) 的首都是 \(capital)")
}

printCapital(for: "France") // 输出: France 的首都是 Paris
printCapital(for: "Canada") // 输出: 未找到 Canada 的首都信息

字典键值获取的最佳实践 #

1. 避免强制解包 #

❌ 不推荐:

let rome = capitals["Italy"]! // 如果键不存在会崩溃

✅ 推荐:

if let rome = capitals["Italy"] {
    // 安全使用
}

2. 使用 default 参数简化代码 #

// 旧方法
var scores = ["Alice": 5, "Bob": 3]
scores["Alice"] = (scores["Alice"] ?? 0) + 1

// 新方法(Swift 4+)
scores["Alice", default: 0] += 1

3. 处理不存在的键 #

// 使用空合运算符
let score = scores["Charlie"] ?? 0

// 使用字典的默认值方法
let defaultValue = scores["Charlie", default: 0]

4. 使用键路径(Swift 5.2+) #

struct Country {
    var name: String
    var capital: String
}

let countries = [
    "FR": Country(name: "France", capital: "Paris"),
    "IT": Country(name: "Italy", capital: "Rome")
]

// 使用键路径获取值
if let italyCapital = countries["IT"]?.capital {
    print(italyCapital) // 输出: Rome
}

完整示例:国家首都查询系统 #

import Foundation

struct CapitalCitySystem {
    private var capitals: [String: String]
    
    init() {
        capitals = [
            "France": "Paris",
            "Italy": "Rome",
            "Japan": "Tokyo",
            "Germany": "Berlin",
            "Spain": "Madrid",
            "China": "Beijing",
            "India": "New Delhi",
            "Brazil": "Brasília",
            "Australia": "Canberra",
            "Canada": "Ottawa"
        ]
    }
    
    func getCapital(for country: String) -> String? {
        capitals[country]
    }
    
    func getCapitalWithDefault(for country: String) -> String {
        capitals[country, default: "未知"]
    }
    
    func searchCapitals(containing searchText: String) -> [String: String] {
        capitals.filter { country, capital in
            country.localizedCaseInsensitiveContains(searchText) ||
            capital.localizedCaseInsensitiveContains(searchText)
        }
    }
    
    mutating func addCapital(country: String, capital: String) {
        capitals[country] = capital
    }
    
    mutating func removeCapital(for country: String) {
        capitals[country] = nil
    }
    
    func printAllCapitals() {
        for (country, capital) in capitals.sorted(by: { $0.key < $1.key }) {
            print("\(country): \(capital)")
        }
    }
}

// 使用示例
var system = CapitalCitySystem()

// 查询首都
if let franceCapital = system.getCapital(for: "France") {
    print("法国的首都是 \(franceCapital)")
}

// 使用默认值查询
let russiaCapital = system.getCapitalWithDefault(for: "Russia")
print("俄罗斯的首都是 \(russiaCapital)") // 输出: 俄罗斯的首都是 未知

// 添加新首都
system.addCapital(country: "Russia", capital: "Moscow")
print(system.getCapital(for: "Russia") ?? "未找到") // 输出: Moscow

// 搜索功能
let searchResults = system.searchCapitals(containing: "a")
print("包含 'a' 的国家/首都:")
for (country, capital) in searchResults {
    print("- \(country): \(capital)")
}

// 删除首都
system.removeCapital(for: "Brazil")
print(system.getCapital(for: "Brazil") ?? "巴西信息已删除") // 输出: 巴西信息已删除

// 打印所有首都
print("\n所有国家及其首都:")
system.printAllCapitals()

总结 #

在 Swift 中获取字典键值有多种方式:

  1. 下标语法​:最常用方式,返回可选值
  2. default 参数​:提供默认值,避免可选类型
  3. 可选绑定​:安全解包可选值
  4. 空合运算符​:提供默认值的简洁方式
  5. 高阶函数​:如 filterfirst(where:) 等

最佳实践:

  • 优先使用可选绑定或空合运算符处理可能不存在的键
  • 使用 default 参数简化计数和累加操作
  • 避免强制解包,防止运行时崩溃
  • 使用键路径访问嵌套字典中的值

通过合理选择获取方式,可以编写出既安全又高效的 Swift 代码。

常用代码示例 #

1. 合并两个字典 #

var dict1 = ["name": "Alice", "age": 25]
let dict2 = ["age": 30, "city": "New York"]

dict1.merge(dict2) { (_, new) in 
    return new 
}
// dict1 = ["name": "Alice", "age": 30, "city": "New York"]

2. 筛选字典中满足条件的键值对 #

let dict = ["A": 10, "B": 20, "C": 15, "D": 5]
let filteredDict = dict.filter { $0.value > 10 }
// filteredDict = ["B": 20, "C": 15]

3. 设置默认值时访问字典 #

let dict = ["name": "Alice"]
let age = dict["age", default: "Not specified"] // age = "Not specified"

4. 创建一个分组的字典 #

let array = [1, 2, 3, 4, 5, 6]
let grouped = Dictionary(grouping: array, by: { $0 % 2 })
// grouped = [0: [2, 4, 6], 1: [1, 3, 5]]

5. 提取不为 nil 的键值(compactMapValues #

let dict = ["key1": "123", "key2": "abc", "key3": "456"]
let numberDict = dict.compactMapValues { Int($0) }
// numberDict = ["key1": 123, "key3": 456]

6. 查找最小/最大值的键值对 #

let dict = ["A": 10, "B": 20, "C": 15]
let maxPair = dict.max(by: { $0.value < $1.value }) 
// maxPair = ("B", 20)

总结 #

Swift 的 Dictionary 提供了强大的键值对管理接口,支持高效的添加、删除、查找和筛选,常用接口包括:

  1. 增删改

    • 添加:updateValue(_:forKey:), merge(_:uniquingKeysWith:)
    • 删除:removeValue(forKey:), removeAll()
  2. 数据提取与遍历

    • 获取:keys, values
    • 遍历:forEach(_:), map(_:)
  3. 查询操作

    • 检查键值对存在性:contains(where:), keys.contains(_:)
  4. 数据变换

    • 筛选:filter(_:)
    • 值映射:mapValues(_:), compactMapValues(_:)
本文共 2932 字,创建于 Jan 2, 2025
相关标签: Swift, Xcode