Dictionary 具有自定义类型键的奇怪Dict行为
我有一个递归函数,它利用一个全局dict来存储遍历树时已经获得的值。然而,至少一些存储在dict中的值似乎消失了!此简化代码显示了问题:Dictionary 具有自定义类型键的奇怪Dict行为,dictionary,julia,Dictionary,Julia,我有一个递归函数,它利用一个全局dict来存储遍历树时已经获得的值。然而,至少一些存储在dict中的值似乎消失了!此简化代码显示了问题: type id level::Int32 x::Int32 end Vdict = Dict{id,Float64}() function getV(w::id) if haskey(Vdict,w) return Vdict[w] end if w.level == 12 retu
type id
level::Int32
x::Int32
end
Vdict = Dict{id,Float64}()
function getV(w::id)
if haskey(Vdict,w)
return Vdict[w]
end
if w.level == 12
return 1.0
end
w.x == -111 && println("dont have: ",w)
local vv = 0.0
for j = -15:15
local wj = id(w.level+1,w.x+j)
vv += getV(wj)
end
Vdict[w] = vv
w.x == -111 && println("just stored: ",w)
vv
end
getV(id(0,0))
输出有许多行,如下所示:
just stored: id(11,-111)
dont have: id(11,-111)
just stored: id(11,-111)
dont have: id(11,-111)
just stored: id(11,-111)
dont have: id(11,-111)
...
我是否犯了愚蠢的错误,或者Julia的dict中是否存在错误?默认情况下,自定义类型随对象标识的相等和散列实现一起出现。由于您的
id
类型是可变的,因此Julia是保守的,并假设您关心区分每个实例与另一个实例(因为它们可能会发生分歧):
Julia不知道您是否关心对象的长期行为或当前值
有两种方法可以使其按您的意愿运行:
Id
的内容。解决这个问题最简单、最直接的方法是将其定义为不可变Id
。现在Id(11,-111)
与Id(11,-111)
的任何其他构造完全无法区分,因为它的值永远不会改变。作为奖励,你可能也会看到更好的表现=
和Base.hash的实现,以便它们只关心当前值:
==(a::Id, b::Id) = a.level == b.level && a.x == b.x
Base.hash(a::Id, h::Uint) = hash(a.level, hash(a.x, h))
正如@StefanKarpinski,这不是可变值的默认值“因为它可以很容易地将某个内容粘贴到dict中,然后对其进行变异并“丢失”。”也就是说,对象的散列值已更改,但字典基于其旧散列值将其存储在某个位置,现在您无法再通过键查找访问该键/值对。即使创建的第二个对象与第一个对象具有相同的原始属性,它也无法找到它,因为字典在找到哈希匹配后会检查相等性。查找该键的唯一方法是将其变回其原始值,或显式要求字典Base.rehash代码>其内容
在这种情况下,我强烈推荐选项1。另请参阅相关的Julia软件包:
==(a::Id, b::Id) = a.level == b.level && a.x == b.x
Base.hash(a::Id, h::Uint) = hash(a.level, hash(a.x, h))