Reputation: 966
having a set of matrices, when looping through them and modifying them, I'm unable to delete them from the 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
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]])
however manual delete works:
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]
What am I missing please? I assumed the g
in the loop behaves like a pointer to certain matrix, but it doesn't. Clearly, I am missing some Julia concept here...
Upvotes: 3
Views: 86
Reputation: 69869
You most likely want to use IdDict
not Set
in this case:
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}()
The difference is that IdDict
makes lookup on matrix identity, while Set
makes lookup on matrix contents.
Note though that IdDict
can store two matrices having identical contents as separate entries if they are not stored in the same memory location (as tested with ===
):
julia> IdDict([1;;] => nothing, [1;;] => nothing)
IdDict{Matrix{Int64}, Nothing} with 2 entries:
[1;;] => nothing
[1;;] => nothing
so you need to choose what kind of behavior you want.
Alternatively you should delete the element from a Set
before mutating it:
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}}()
To expand on the problem more see:
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
So although x
shows that it stores a
the lookup of a
fails, because Set
performs the lookup based on hash
value of a
computed at the time a
was stored in x
and if you change the contents of a
its hash
changes.
In short:
Set
, but then do not mutate them for lookup;IdDict
that does lookup using object identity not object value.Upvotes: 3