Julia 中矩阵集的奇怪行为
strange behaviour of Set of Matrices in Julia
有一组矩阵,当遍历它们并修改它们时,我无法从集合中删除它们:
julia> grids = Set([[1 2;3 4],[3 4;5 6]])
Set{Matrix{Int64}} with 2 elements:
[1 2; 3 4]
[3 4; 5 6]
julia> for g in grids
g[g .== 3] .= 0
println(g)
println(grids)
delete!(grids,g)
end
[1 2; 0 4]
Set([[1 2; 0 4], [3 4; 5 6]])
[0 4; 5 6]
Set([[1 2; 0 4], [0 4; 5 6]])
julia> println(grids)
Set([[1 2; 0 4], [0 4; 5 6]])
但是手动删除有效:
julia> grids = Set([[1 2;3 4],[3 4;5 6]])
Set{Matrix{Int64}} with 2 elements:
[1 2; 3 4]
[3 4; 5 6]
julia> delete!(grids, [1 2;3 4])
Set{Matrix{Int64}} with 1 element:
[3 4; 5 6]
请问我错过了什么?我假设循环中的 g
表现得像指向某个矩阵的指针,但事实并非如此。显然,我在这里遗漏了一些 Julia 概念......
在这种情况下,您很可能想使用 IdDict
而不是 Set
:
julia> grids = IdDict([[1 2;3 4],[3 4;5 6]] .=> nothing)
IdDict{Matrix{Int64}, Nothing} with 2 entries:
[1 2; 3 4] => nothing
[3 4; 5 6] => nothing
julia> for g in keys(grids)
g[g .== 3] .= 0
println(g)
println(grids)
delete!(grids,g)
end
[1 2; 0 4]
IdDict([1 2; 0 4] => nothing, [3 4; 5 6] => nothing)
[0 4; 5 6]
IdDict([0 4; 5 6] => nothing)
julia> grids
IdDict{Matrix{Int64}, Nothing}()
区别在于IdDict
查找矩阵恒等式,而Set
查找矩阵内容。
请注意,尽管 IdDict
可以将两个具有相同内容的矩阵存储为单独的条目,如果它们没有存储在相同的内存位置(使用 ===
进行测试):
julia> IdDict([1;;] => nothing, [1;;] => nothing)
IdDict{Matrix{Int64}, Nothing} with 2 entries:
[1;;] => nothing
[1;;] => nothing
所以你需要选择你想要什么样的行为。
或者你应该在改变它之前从 Set
中删除元素:
julia> grids = Set([[1 2;3 4],[3 4;5 6]])
Set{Matrix{Int64}} with 2 elements:
[1 2; 3 4]
[3 4; 5 6]
julia> for g in grids
println(grids)
delete!(grids,g)
g[g .== 3] .= 0
println(g)
end
Set([[1 2; 3 4], [3 4; 5 6]])
[1 2; 0 4]
Set([[3 4; 5 6]])
[0 4; 5 6]
julia> grids
Set{Matrix{Int64}}()
要进一步扩展问题,请参阅:
julia> a = [1]
1-element Vector{Int64}:
1
julia> x = Set([a])
Set{Vector{Int64}} with 1 element:
[1]
julia> a in x
true
julia> a[1] = 2
2
julia> x
Set{Vector{Int64}} with 1 element:
[2]
julia> a in x
false
所以尽管 x
显示它存储 a
a
的查找失败,因为 Set
根据 hash
值执行查找 [在 a
时计算的 =22=] 存储在 x
中,如果您更改 a
的内容,它的 hash
也会更改。
简而言之:
- 您可以将可变值存储在
Set
中,但不要为了查找而改变它们;
- 或者,您可以使用
IdDict
,它使用对象标识而不是对象值进行查找。
有一组矩阵,当遍历它们并修改它们时,我无法从集合中删除它们:
julia> grids = Set([[1 2;3 4],[3 4;5 6]])
Set{Matrix{Int64}} with 2 elements:
[1 2; 3 4]
[3 4; 5 6]
julia> for g in grids
g[g .== 3] .= 0
println(g)
println(grids)
delete!(grids,g)
end
[1 2; 0 4]
Set([[1 2; 0 4], [3 4; 5 6]])
[0 4; 5 6]
Set([[1 2; 0 4], [0 4; 5 6]])
julia> println(grids)
Set([[1 2; 0 4], [0 4; 5 6]])
但是手动删除有效:
julia> grids = Set([[1 2;3 4],[3 4;5 6]])
Set{Matrix{Int64}} with 2 elements:
[1 2; 3 4]
[3 4; 5 6]
julia> delete!(grids, [1 2;3 4])
Set{Matrix{Int64}} with 1 element:
[3 4; 5 6]
请问我错过了什么?我假设循环中的 g
表现得像指向某个矩阵的指针,但事实并非如此。显然,我在这里遗漏了一些 Julia 概念......
在这种情况下,您很可能想使用 IdDict
而不是 Set
:
julia> grids = IdDict([[1 2;3 4],[3 4;5 6]] .=> nothing)
IdDict{Matrix{Int64}, Nothing} with 2 entries:
[1 2; 3 4] => nothing
[3 4; 5 6] => nothing
julia> for g in keys(grids)
g[g .== 3] .= 0
println(g)
println(grids)
delete!(grids,g)
end
[1 2; 0 4]
IdDict([1 2; 0 4] => nothing, [3 4; 5 6] => nothing)
[0 4; 5 6]
IdDict([0 4; 5 6] => nothing)
julia> grids
IdDict{Matrix{Int64}, Nothing}()
区别在于IdDict
查找矩阵恒等式,而Set
查找矩阵内容。
请注意,尽管 IdDict
可以将两个具有相同内容的矩阵存储为单独的条目,如果它们没有存储在相同的内存位置(使用 ===
进行测试):
julia> IdDict([1;;] => nothing, [1;;] => nothing)
IdDict{Matrix{Int64}, Nothing} with 2 entries:
[1;;] => nothing
[1;;] => nothing
所以你需要选择你想要什么样的行为。
或者你应该在改变它之前从 Set
中删除元素:
julia> grids = Set([[1 2;3 4],[3 4;5 6]])
Set{Matrix{Int64}} with 2 elements:
[1 2; 3 4]
[3 4; 5 6]
julia> for g in grids
println(grids)
delete!(grids,g)
g[g .== 3] .= 0
println(g)
end
Set([[1 2; 3 4], [3 4; 5 6]])
[1 2; 0 4]
Set([[3 4; 5 6]])
[0 4; 5 6]
julia> grids
Set{Matrix{Int64}}()
要进一步扩展问题,请参阅:
julia> a = [1]
1-element Vector{Int64}:
1
julia> x = Set([a])
Set{Vector{Int64}} with 1 element:
[1]
julia> a in x
true
julia> a[1] = 2
2
julia> x
Set{Vector{Int64}} with 1 element:
[2]
julia> a in x
false
所以尽管 x
显示它存储 a
a
的查找失败,因为 Set
根据 hash
值执行查找 [在 a
时计算的 =22=] 存储在 x
中,如果您更改 a
的内容,它的 hash
也会更改。
简而言之:
- 您可以将可变值存储在
Set
中,但不要为了查找而改变它们; - 或者,您可以使用
IdDict
,它使用对象标识而不是对象值进行查找。