2014-10-20 119 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