在How to hash lists?我被告知我应该首先转换为元组,例如[1,2,3,4,5]
至(1,2,3,4,5)
。
所以第一个不能被哈希,但第二个可以。为什么 * ?
* 我不是在寻找详细的技术解释,而是为了直觉
答案 0 :(得分:42)
主要是因为元组是不可变的。假设以下工作:
>>> l = [1, 2, 3]
>>> t = (1, 2, 3)
>>> x = {l: 'a list', t: 'a tuple'}
现在,当您l.append(4)
时会发生什么?您已修改字典中的密钥!远道而来!如果您熟悉散列算法的工作方式,这应该会让您感到害怕。另一方面,元组绝对是不可变的。 t += (1,)
可能看起来像修改元组,但实际上并非如此:它只是创建一个 new 元组,保持字典键不变。
答案 1 :(得分:7)
你可以完全做到这一点,但我打赌你不会喜欢这些效果。
from functools import reduce
from operator import xor
class List(list):
def __hash__(self):
return reduce(xor, self)
现在让我们看看会发生什么:
>>> l = List([23,42,99])
>>> hash(l)
94
>>> d = {l: "Hello"}
>>> d[l]
'Hello'
>>> l.append(7)
>>> d
{[23, 42, 99, 7]: 'Hello'}
>>> l
[23, 42, 99, 7]
>>> d[l]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: [23, 42, 99, 7]
编辑:所以我想到了更多。如果您将列表的id作为其哈希值返回,则可以使上述示例有效:
class List(list):
def __hash__(self):
return id(self)
在这种情况下,d[l]
会为您'Hello'
,但d[[23,42,99,7]]
和d[List([23,42,99,7])]
都不会(因为您正在创建新的[Ll]ist
答案 2 :(得分:4)
由于列表是可变的,如果你修改它,你也会修改它的哈希值,这会破坏哈希(比如set或dict键)。
答案 3 :(得分:4)
因为列表是可变的而且元组不是。
答案 4 :(得分:1)
答案很好。原因是可变性。如果我们可以将字典中的list用作键; (或任何可变对象),那么我们就可以通过(意外或有意地)更改键来更改键。这将导致字典中键的哈希值发生变化,因此,我们将无法通过该键从该数据结构中检索该值。 通过将哈希值和哈希表映射到存储实数值条目的索引,可以轻松地映射大数据。
在此处详细了解它们:-
答案 5 :(得分:0)
并非每个元组都是hashable。例如,元组包含list作为元素。
x = (1,[2,3])
print(type(x))
print(hash(x))