2014-10-20 80 views
2

我遇到了一个问题,试图使用其键是包含复合类型的元组的字典。Julia:包含复合类型的包含元组键的字典

下面是一个小例子来复制我的问题:

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工作,但由于某些原因的字典是没有的。

有谁知道发生了什么事?谢谢。

+0

我向'isequal'和'hash'添加了一些打印语句。出于某种原因,添加到字典导致它调用'isequal'(为什么不哈希?)和用d [r]检查字典不会导致被调用。 – Mageek 2014-10-20 03:36:56

+0

应该导入hash和isequal以使它们过载。导入语句不在代码片段中(它在Iain的下面)。这是否解释了差异? – 2014-10-20 19:27:29

+0

你是正确的,他们需要进口。我确实有,但应该把它放在那里。我会添加它。 – Mageek 2014-10-20 21:16:22

回答

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

有趣。我在版本0.3.1(2014-09-21 21:30 UTC) – Mageek 2014-10-20 04:40:03

+0

请注意,你用字典运行它,其中键是类型T.我的例子有一个字典,其中的键是元组:(T,Int)。你可以尝试运行吗? – Mageek 2014-10-20 16:37:29

+0

是的,我说我可以重新创建你的问题,并且这个问题不会发生在这个非常相似的例子中。我的观点是,我认为你应该提交一个JuliaLang /朱莉亚问题。我已经编辑了我的答案,以便更清楚。 – IainDunning 2014-10-20 16:44:38

0

该问题可以通过为每个hash & isequal功能来解决复合类型而不是整个元组。

如果关键是(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 

如果你想在原来的配方工作,你必须指定基地。使用可选的第二个参数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 
+0

我不明白为什么原始问题中的版本不应该工作? – IainDunning 2014-10-20 18:32:03

+0

我只是偶然发现了正确的解决方案:事实证明,您必须实现哈希以支持可选的第二个参数'h :: Uint64'。不知道为什么这一定会修复它,但它确实如此。 – Mageek 2014-10-20 21:24:42

+0

伟大的一点,这实际上记录在这里:http://docs.julialang.org/en/latest/stdlib/base/?highlight=hash#Base.hash。我也更新了我的答案。 – IainDunning 2014-10-20 21:27:21