现在位置: 首页 > Julia 教程 > 正文

Julia 字典和集合

除了数组元组,Julia 还提供了两种常用的集合:字典(Dict)和 Set(无序集合)。


字典

字典是一种可变容器模型,且可存储任意类型对象。

字典的每个键值对用 => 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中。

创建字典

创建字典的语法格式如下:

Dict("key1" => value1, "key2" => value2, ..., "keyn" => valuen)

以下实例创建一个简单的字典,键 A 对应的值为 1,键 B 对应的值为 2:

实例

julia> D = Dict("A"=>1, "B"=>2)
Dict{String, Int64} with 2 entries:
  "B" => 2
  "A" => 1

Julia 会自动推断键和值的类型,如上例为 Dict{String, Int64}。也可以显式指定类型:

实例

julia> D = Dict{String,Float64}("A"=>1, "B"=>2)
Dict{String, Float64} with 2 entries:
  "B" => 2.0
  "A" => 1.0

使用推导式来创建一个字典:

实例

julia> first_dict = Dict(string(x) => sind(x) for x = 0:5:90)
Dict{String, Float64} with 19 entries:
  "85" => 0.996195
  "20" => 0.34202
  ...

访问字典

使用方括号加键来访问对应的值:

实例

julia> D = Dict("A"=>1, "B"=>2);

julia> D["A"]
1

# 访问不存在的键会抛出 KeyError
julia> D["X"]
ERROR: KeyError: key "X" not found

如果想在不存在的键上返回默认值而不报错,使用 get() 函数;get!() 还会把默认值写回字典:

实例

julia> get(D, "X", 0)      # 键不存在返回默认值 0
0

julia> get(D, "A", 0)      # 键存在返回实际值
1

julia> get!(D, "C", 3)     # C 不存在,写入并返回默认值
3

添加与修改

字典中的键是唯一的,如果我们为一个已经存在的键分配一个值,不会创建新的键,而是修改现有键的值:

实例

julia> D["C"] = 3      # 添加新的键值对
3

julia> D["A"] = 100    # 修改已有键的值
100

julia> D
Dict{String, Int64} with 3 entries:
  "B" => 2
  "A" => 100
  "C" => 3

删除键值对

我们可以使用 delete!() 函数删除已存在字典的键:

实例

julia> delete!(D, "C")
Dict{String, Int64} with 2 entries:
  "B" => 2
  "A" => 100

pop!(D, key) 可以删除键值对并返回被删除的值。

查询键

我们可以使用 haskey() 函数来检查字典是否包含指定的 key:

实例

julia> haskey(D, "A")
true

julia> haskey(D, "Z")
false

# in 检查的是完整的键值对
julia> in(("A" => 100), D)
true

julia> keys(D)     # 获取所有键
KeySet for a Dict{String, Int64} with 2 entries. Keys:
  "B"
  "A"

查询值与遍历

我们可以使用 values() 查看字典所有值,并将字典作为可迭代对象来遍历键值对:

实例

julia> values(D)
ValueIterator for a Dict{String, Int64} with 2 entries. Values:
 2
 100

julia> for kv in D
           println(kv)
       end
"B" => 2
"A" => 100

# 也可以同时解构键和值
julia> for (k, v) in D
           println("键 $k 的值是 $v")
       end
键 B 的值是 2
键 A 的值是 100

合并字典

merge() 返回合并后的新字典,键冲突时后面的字典覆盖前面的值;merge!() 则原地合并到第一个字典:

实例

julia> d1 = Dict("a"=>1, "b"=>2);

julia> d2 = Dict("b"=>3, "c"=>4);

julia> merge(d1, d2)     # b 的值被 d2 覆盖
Dict{String, Int64} with 3 entries:
  "a" => 1
  "b" => 3
  "c" => 4

# mergewith 可以自定义冲突时的合并规则
julia> mergewith(+)(d1, d2)     # 冲突时相加
Dict{String, Int64} with 3 entries:
  "a" => 1
  "b" => 5
  "c" => 4

字典排序

字典本身是无序的,但我们可以使用 sort() 函数对键排序后遍历:

实例

julia> runoob_dict = Dict("R" => 100, "S" => 220, "T" => 350, "U" => 400, "V" => 575, "W" => 670);

julia> for key in sort(collect(keys(runoob_dict)))
           println("$key => $(runoob_dict[key])")
       end
R => 100
S => 220
T => 350
U => 400
V => 575
W => 670

如果需要字典始终保持排序状态,可以使用 DataStructures 包中的 SortedDict 数据类型。

使用第三方包需要先安装它,在 REPL 中输入符号 ],进入 pkg 模式:

julia> ]               # 输入 ] 就进入 pkg 模式

添加包的语法格式为 add 包名,以下我们添加 DataStructures 包:

(@v1.10) pkg> add DataStructures

未注册的包,可以直接指定 url:

pkg> add https://github.com/fredrikekre/ImportMacros.jl

本地包:

pkg> add 本地路径/包名.jl

实例

julia> import DataStructures

julia> runoob_dict = DataStructures.SortedDict("S" => 220, "T" => 350, "U" => 400, "V" => 575, "W" => 670)
DataStructures.SortedDict{String, Int64, Base.Order.ForwardOrdering} with 5 entries:
  "S" => 220
  "T" => 350
  ...

julia> runoob_dict["R"] = 100
100

julia> runoob_dict     # 键始终保持有序
DataStructures.SortedDict{String, Int64, Base.Order.ForwardOrdering} with 6 entries:
  "R" => 100
  "S" => 220
  ...

Set(集合)

Julia Set(集合)是没有重复对象的数据集,所有的元素都是唯一的。

以下是 Set 和其他类型的集合之间的区别:

  • Set 中的元素是唯一的
  • Set 中元素的顺序不重要

创建 Set 集合

借助 Set 构造函数,我们可以创建如下集合:

实例

julia> var_site = Set()
Set{Any}()

julia> num_primes = Set{Int64}()
Set{Int64}()

julia> var_site = Set{String}(["Google", "Runoob", "Taobao"])
Set{String} with 3 elements:
  "Google"
  "Taobao"
  "Runoob"

我们可以使用 push!() 函数添加集合元素:

实例

julia> push!(var_site, "Wiki")
Set{String} with 4 elements:
  "Google"
  "Wiki"
  "Taobao"
  "Runoob"

# 添加重复元素不会有任何效果
julia> push!(var_site, "Runoob")
Set{String} with 4 elements:
  "Google"
  "Wiki"
  "Taobao"
  "Runoob"

我们可以使用 in() 函数查看元素是否存在于集合中:

实例

julia> in("Runoob", var_site)
true

julia> "Zhihu" in var_site     # in 的中缀写法
false

集合运算

并集、交集和差集是我们可以对集合常用的一些操作,这些操作对应的函数是 union()、intersect()setdiff()

实例

julia> A = Set{String}(["red", "green", "blue", "black"]);

julia> B = Set(["red", "orange", "yellow", "green", "blue", "indigo", "violet"]);

并集:两个集合所有的元素合并在一起组成的集合:

实例

julia> union(A, B)
Set{String} with 8 elements:
  "indigo"
  "green"
  "black"
  "yellow"
  ...

交集:既属于 A 又属于 B 的元素组成的集合:

实例

julia> intersect(A, B)
Set{String} with 3 elements:
  "blue"
  "green"
  "red"

差集:属于 A 但不属于 B 的元素:

实例

julia> setdiff(A, B)
Set{String} with 1 element:
  "black"

此外还有子集判断函数 issubset()(运算符 )和判断两个集合是否相等 issetequal()

实例

julia> Set([1, 2])Set([1, 2, 3])
true

julia> issubset(Set([1, 2]), Set([1, 2, 3]))
true

julia> issetequal(Set([1, 2]), Set([2, 1]))    # 与顺序无关
true

提示:union、intersect、setdiff 同样适用于数组,常用于快速去重:unique(A) 返回去除重复元素后的数组。


字典常用函数速查

函数描述
D[k]取键 k 对应的值,不存在时抛 KeyError
get(D, k, default)取值,键不存在时返回 default
get!(D, k, default)取值,键不存在时写入 default 并返回
haskey(D, k)判断键是否存在
delete!(D, k)删除键值对
pop!(D, k)删除键值对并返回值
keys(D) / values(D)所有键 / 所有值
length(D)键值对个数
merge(D1, D2)合并字典,后者覆盖前者