Julia 字典(Dict)与集合(Set)完全指南(中文版)
“高效、类型安全、无序存储” —— Julia 的哈希容器性能卓越
一、总览对比
| 特性 | Dict{K,V} | Set{T} |
|---|---|---|
| 存储 | 键值对 | 唯一元素 |
| 顺序 | 无序 | 无序 |
| 重复 | 键唯一 | 元素唯一 |
| 查找 | O(1) 平均 | O(1) 平均 |
| 内存 | 稍高 | 稍低 |
| primordial | 键值映射 | 去重、成员测试 |
二、字典 Dict —— 键值对存储
1. 创建字典
# 基本语法
d1 = Dict("a" => 1, "b" => 2, "c" => 3)
# 空字典(指定类型)
d2 = Dict{String, Int}()
d3 = Dict{String, Float64}("pi" => 3.14)
# 类型推断
d4 = Dict("x" => 1, "y" => 2.0) # Dict{String, Float64}
2. 访问与修改
d = Dict("name" => "Julia", "version" => 1.10)
# 读取
d["name"] # "Julia"
get(d, "name", "unknown") # "Julia"
get(() -> "unknown", d, "name") # 函数式默认值
# 修改
d["version"] = 1.11
d["year"] = 2012
# 删除
delete!(d, "year")
pop!(d, "version", nothing) # 删除并返回
# 检查键
haskey(d, "name") # true
"name" in keys(d) # true
3. 遍历字典
for (k, v) in d
println("$k => $v")
end
for k in keys(d)
println(k)
end
for v in values(d)
println(v)
end
4. 合并字典
d1 = Dict("a" => 1, "b" => 2)
d2 = Dict("b" => 20, "c" => 3)
merge(d1, d2) # {"a"=>1, "b"=>20, "c"=>3}
merge!(d1, d2) # 修改 d1
三、集合 Set —— 唯一元素集合
1. 创建集合
# 基本语法
s1 = Set([1, 2, 2, 3, 3, 4]) # Set{Int64} with 4 elements: {1,2,3,4}
# 空集合
s2 = Set{Int}()
# 类型推断
s3 = Set(["apple", "banana", "apple"]) # Set{String}
2. 添加与删除
s = Set([1, 2, 3])
push!(s, 4) # {1,2,3,4}
push!(s, 4) # 无变化(已存在)
delete!(s, 3) # {1,2,4}
pop!(s) # 移除并返回任意元素(如 1)
3. 成员测试
4 in s # true
inset(4, s) # 同上
4. 集合运算
A = Set([1, 2, 3, 4])
B = Set([3, 4, 5, 6])
union(A, B) # 并集 {1,2,3,4,5,6}
intersect(A, B) # 交集 {3,4}
setdiff(A, B) # 差集 {1,2}
issubset(A, B) # A ⊆ B ? false
符号写法:
A ∪ B, A ∩ B, A \ B
四、字典与集合的类型参数
# 明确指定类型(推荐用于性能)
d = Dict{String, Int}("count" => 100)
# 任意键值(不推荐)
d_any = Dict("a" => 1, 2 => "b") # Dict{Any, Any}
性能提示:使用具体类型避免
Any,提升速度与内存效率
五、OrderedDict 与 OrderedSet(有序版本)
需安装:
] add OrderedCollections
using OrderedCollections
od = OrderedDict("c" => 3, "a" => 1, "b" => 2)
# 保持插入顺序:c, a, b
os = OrderedSet([3, 1, 2])
# 保持插入顺序:3, 1, 2
六、性能对比(哈希 vs 数组)
using BenchmarkTools
arr = 1:1_000_000
dict = Dict(i => i for i in arr)
set = Set(arr)
@btime 500_000 in arr; # ~100 μs
@btime haskey(dict, 500_000); # ~10 ns
@btime 500_000 in set; # ~10 ns
结论:查找 O(1) vs O(n) → 字典/集合完胜!
七、综合示例:词频统计
function word_frequency(text::AbstractString)
freq = Dict{String, Int}()
for word in split(lowercase(text), r"\W+"; keepempty=false)
freq[word] = get(freq, word, 0) + 1
end
return freq
end
text = "To be or not to be, that is the question."
word_frequency(text)
# Dict("to" => 2, "be" => 2, "or" => 1, ...)
八、综合示例:图的邻接表表示
# 无向图
graph = Dict{String, Set{String}}()
function add_edge!(g, a, b)
get!(Set{String}, g, a) |> x -> push!(x, b)
get!(Set{String}, g, b) |> x -> push!(x, a)
end
add_edge!(graph, "A", "B")
add_edge!(graph, "A", "C")
add_edge!(graph, "B", "D")
graph
# Dict("A" => Set(["B","C"]), "B" => Set(["A","D"]), ...)
九、字典与集合速查表
| 操作 | Dict | Set |
|---|---|---|
| 创建 | Dict(k=>v, ...) | Set([1,2,3]) |
| 添加 | d[k] = v | push!(s, x) |
| 删除 | delete!(d, k) | delete!(s, x) |
| 查找 | haskey(d, k) | x in s |
| 获取 | get(d, k, def) | |
| 遍历 | keys(d), values(d) | for x in s |
| 合并 | merge(d1, d2) | union(s1, s2) |
| 交集 | intersect(s1, s2) | |
| 差集 | setdiff(s1, s2) |
十、小练习(立即上手)
- 实现
invert_dict(d)反转键值对(值唯一) - 写函数
common_friends(graph, a, b)返回共同好友集合 - 实现
group_by(arr, f)按函数返回值分组(返回 Dict) - 性能测试:用
Set去重 100 万随机数 vs 数组 - 实现
DefaultDict(不存在的键返回默认值)
答案示例
# 1. 反转字典
invert_dict(d) = Dict(v => k for (k,v) in d)
# 2. 共同好友
function common_friends(graph, a, b)
get(graph, a, Set()) ∩ get(graph, b, Set())
end
# 3. group_by
function group_by(arr, f)
result = Dict{Any, Vector{eltype(arr)}}()
for x in arr
k = f(x)
push!(get!(Vector{eltype(arr)}, result, k), x)
end
return result
end
group_by(1:10, iseven)
# Dict(false => [1,3,5,7,9], true => [2,4,6,8,10])
# 4. 去重性能
using Random
data = rand(1:100_000, 1_000_000)
@btime unique(data); # ~50 ms
@btime Set(data); # ~15 ms
# 5. DefaultDict
struct DefaultDict{K,V,F} <: AbstractDict{K,V}
dict::Dict{K,V}
default::F
end
DefaultDict(default) = DefaultDict(Dict(), default)
function Base.getindex(d::DefaultDict{K,V}, k) where {K,V}
get!(d.dict, k) do
d.default()
end
end
十一、常见错误与避坑
| 错误 | 正确做法 |
|---|---|
d["new_key"] 访问不存在的键 | 用 get(d, k, def) 或 haskey |
Set([1, 2.0]) 混用类型 | 集合元素类型统一 |
push!(d, k=>v) | d[k] = v |
字典键为可变对象(如 [1,2]) | 不可变键(如 Tuple) |
# 正确:用元组做复合键
d = Dict()
d[(1, 2)] = "A"
d[(3, 4)] = "B"
十二、进阶:符号字典 Dict{Symbol, Any}
config = Dict(:debug => true, :port => 8000, :timeout => 30)
config[:debug] = false
常用于配置、参数传递
恭喜!你已精通 Julia 字典与集合!
现在你可以:
- 用 Dict 构建配置系统、缓存、图结构
- 用 Set 实现去重、成员测试、集合运算
- 写出高性能数据处理管道
- 设计优雅的 API 参数系统
下一站推荐
| 主题 | 为什么学 |
|---|---|
NamedTuple | 轻量带名元组 |
struct | 自定义类型 |
DataFrames | 表格数据 |
JSON.jl | 序列化字典 |
Caching | 字典缓存 |
需要我:
- 写一个 配置文件解析器(.json/.toml)?
- 实现 LRU 缓存(用
Dict+OrderedDict)? - 构建 图算法库(DFS/BFS)?
- 对比 Dict vs NamedTuple 性能?
随时告诉我!