2009-08-04 137 views
1

我有dictint S,float S,string S作爲密鑰的實例中,但問題是當有aintb作爲floatfloat(a) == b,那麼他們的散列值是相同的,那就是我不想得到的,因爲我需要唯一的散列值來獲得相應的值。問題的散列函數:散列(1)==散列(1.0)

例子:

d = {1:'1', 1.0:'1.0', '1':1, '1.0':1.0} 
d[1] == '1.0' 
d[1.0] == '1.0' 
d['1'] == 1 
d['1.0'] == 1.0 

我需要的是:

d = {1:'1', 1.0:'1.0', '1':1, '1.0':1.0} 
d[1] == '1' 
d[1.0] == '1.0' 
d['1'] == 1 
d['1.0'] == 1.0 
+2

你不能做到這一點。 1。0 == 1 – 2009-08-04 16:19:51

回答

7

由於1 == 1.0,如果它是hash(1) != hash(1.0)的情況下,它將可怕地破壞哈希(因此,字典和集)的語義。更一般地說,對於所有的xy(當然沒有條件需要相反的含義),x == y暗示hash(x) == hash(y)必定總是如此。

因此,你的字典d只有三個條目,因爲你在字典顯示中寫的第二個覆蓋第一個條目。如果您需要強制平等僅容納相同類型之間(而不是數字更普遍),你需要的包裝,如:

class W(object): 

    def __init__(self, x): 
    self.x = x 
    self.t = type(x) 

    def __eq__(self, other): 
    t = type(other) 
    if t != type(self): 
     return False 
    return self.x == other.x and self.t == other.t 

    def __hash__(self): 
    return hash(self.x)^hash(self.t) 

    def __getattr__(self, name): 
    return getattr(self.x, name) 

根據您的具體需求,你也可能需要重寫其他方法(其他比較方法,如__cmp____le__,算術方法,__repr__等)。無論如何,這將允許你建立一個類似於你需要的字典,只需使用W(1)而不是空的1W(1.0)而不是空的1.0(你可能不需要包裝非數字,儘管如果你選擇這樣做,並且如果所有的鍵都被平等地包裹,它可以緩解從字典中檢索)。

+0

包裝物體可能被認爲是一種解決方案,它非常接近我所需要的。無論如何,我想知道如下:h = hash('a'); d = {'a':1,h:2};結果是d ['a']!= d [h],因爲密鑰的散列值相同,但它們的類型不相同,這意味着dict方法getitem同時檢查密鑰的哈希值和密鑰的類型。如果是這樣,爲什麼它不完全相同的整數和浮點數? – mtasic85 2009-08-05 10:45:45

1

這不會解決你的問題,但是從Python 2.6's number documentation

實現者必須小心,以平等數字相同並將它們散列爲相同的值。

你可以通過使浮動1.00001,或類似的東西嗎?

6

使用float作爲字典鍵是'不明智的',這是不可能保證兩個浮點數將計算爲相同的值。

最好的辦法是將密鑰乘以預定的小數位數並將該整數用作密鑰。

編輯:對不起,你似乎不想使用真正的數字鍵的字典,你只是想根據輸入的類型格式化輸出?

+0

好點,但我也意識到我可以爲所有關鍵類型創建帶有分隔字符的新類,加上其他所有類型的類,以防我需要它們,其中__setitem__,__getitem__和__delitem__方法可以確定哪個詞典用於存儲鍵和值。 – mtasic85 2009-08-04 16:32:03

2

如果你真的只需要知道其中的差別,也許做喜歡的事的hackish:

x = '1' 
y = 1 

hash(type(x) + x) != hash(type(y) + y)