【问题标题】:Julia: Dictionary with Tuple keys containing Composite TypesJulia:带有包含复合类型的元组键的字典
【发布时间】:2014-10-20 03:23:51
【问题描述】:

我在尝试使用其键是包含复合类型的元组的字典时遇到了问题。

这是一个复制我的问题的最小示例:

import Base: hash, isequal    

type T
    a :: Int
    b :: Int
end

function isequal(A::(T,Int), B::(T,Int))
    A[1].a == B[1].a && A[1].b == B[1].b && A[2] == B[2]
end
function hash(A::(T,Int))
    hash(A[1].a + A[1].b + A[2])
end

d = Dict{(T,Int),Int}()

d[(T(1,1),1)] = 1
d[(T(2,2),2)] = 2

r = (T(2,2),2)

for k in keys(d)
    println(isequal(r, k) && hash(r) == hash(k))
end
println(d[r])

运行此结果:

false
true
ERROR: key not found: (T(2,2),2)

所以isequalhash 有效,但由于某种原因,dict 无效。

有人知道发生了什么吗?谢谢。

【问题讨论】:

  • 我在isequalhash 中添加了一些打印语句。由于某种原因,添加到字典会导致它调用isequal(为什么不散列?)并使用d[r]检查字典不会导致调用。
  • hash 和 isequal 应该被导入以使它们重载。 import 语句不在 sn-p 中(它在 Iain 的下面)。这是否解释了差异?
  • 您说得对,它们需要导入。我确实有,但应该把它放在那里。我会添加它。

标签: julia


【解决方案1】:

在这种情况下,我不太了解元组的类型和调度,但基本上是you need to implement the two argument form of hash for this case。作为比较点,以下非常相似的代码按预期工作,没有两个参数形式:

type T
    a::Int
    b::Int
end

function Base.isequal(A::T, B::T)
    println("isequal", A, " ", B)
    A.a == B.a && A.b == B.b
end
function Base.hash(A::T)
    println("hash", A)
    hash(A.a + A.b)
end

d = Dict{T,Int}()

d[T(1,1)] = 1
d[T(2,2)] = 2

println("test")
r = T(2,2)
println(d[r])

有输出

isequalT(1,1) T(1,1)
hashT(1,1)
isequalT(2,2) T(2,2)
hashT(2,2)
test
hashT(2,2)
isequalT(2,2) T(2,2)
2

【讨论】:

  • 有趣。我使用的是 0.3.1 版(2014-09-21 21:30 UTC)
  • 请注意,您使用 dict 运行它,其中键为 T 类型。我的示例有一个 dict,其中键为元组:(T,Int)。您可以尝试运行它吗?
  • 是的,我是说我可以重现您的问题,并且这个非常相似的示例不会出现问题。我的观点是,我认为您应该提交 JuliaLang/julia 问题。我已经编辑了我的答案以更清楚。
【解决方案2】:

可以通过为每个复合类型而不是整个元组创建 hashisequal 函数来解决问题。

如果你的密钥是(T,Int):

而不是这个:

function isequal(A::(T,Int), B::(T,Int))
    A[1].a == B[1].a && A[1].b == B[1].b && A[2] == B[2]
end
function hash(A::(T,Int))
    hash(A[1].a + A[1].b + A[2])
end

这样做:

function isequal(A::T, B::T)
    A.a == B.a && A.b == B.b
end
function hash(A::T)
    hash(A.a + A.b)
end

如果您希望原始公式起作用,则必须使用可选的第二个参数指定 Base.hash:h::Uint64:

function isequal(A::(T,Int), B::(T,Int))
    A[1].a == B[1].a && A[1].b == B[1].b && A[2] == B[2]
end
function hash(A::(T,Int))
    hash(A[1].a + A[1].b + A[2])
end
function hash(A::(T,Int), h::Uint64)
    hash(A[1].a + A[1].b + A[2] + h)
end

【讨论】:

  • 我不明白为什么您原来问题中的版本不应该工作?
  • 我偶然发现了正确的解决方案:事实证明,您必须实现散列以支持可选的第二个参数h::Uint64。不知道为什么这一定会解决它,但确实如此。
  • 好点,这实际上记录在这里:docs.julialang.org/en/latest/stdlib/base/…。我也更新了我的答案。
猜你喜欢
  • 2017-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多