What's a correct and good way to implement __hash__()?
实施
我说的是一个函数,它返回一个哈希代码,然后将对象插入哈希表(又名字典)。
由于
实现
下面是一个使用键进行哈希和相等的示例:
1 2 3 4 5 6 7 8 9 | class A: def __key(self): return (self.attr_a, self.attr_b, self.attr_c) def __hash__(self): return hash(self.__key()) def __eq__(self, other): return isinstance(self, type(other)) and self.__key() == other.__key() |
另外,
约翰米利金提出了一个类似的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class A(object): def __init__(self, a, b, c): self._a = a self._b = b self._c = c def __eq__(self, othr): return ((self._a, self._b, self._c) == (othr._a, othr._b, othr._c)) def __hash__(self): return hash((self._a, self._b, self._c)) |
。
这个解决方案的问题在于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class B(object): def __init__(self, a, b, c): self._a = a self._b = b self._c = c def __eq__(self, othr): return (isinstance(othr, type(self)) and (self._a, self._b, self._c) == (othr._a, othr._b, othr._c)) def __hash__(self): return (hash(self._a) ^ hash(self._b) ^ hash(self._c) ^ hash((self._a, self._b, self._c))) |
额外的好处:为了更好的衡量,我们投入了更强大的
更新:正如Blckknght指出的,更改A、B和C的顺序可能会导致问题。我添加了一个额外的
微软研究院的保罗·拉森研究了各种各样的哈希函数。他告诉我的
1 2 | for c in some_string: hash = 101 * hash + ord(c) |
在各种各样的琴弦上都表现得出奇的好。我发现类似的多项式技术对于计算不同子字段的散列很有效。
我可以试着回答你问题的第二部分。
冲突可能不是由哈希代码本身引起的,而是由将哈希代码映射到集合中的索引引起的。例如,散列函数可以返回从1到10000的随机值,但如果散列表只有32个条目,则插入时会发生冲突。
此外,我认为冲突将由集合内部解决,并且有许多方法可以解决冲突。最简单(也是最糟糕)的是,给定一个要在索引i处插入的条目,向i添加1,直到找到一个空点并插入其中。然后检索的工作方式相同。这会导致某些条目的检索效率低下,因为您可能有一个需要遍历整个集合才能找到的条目!
其他冲突解决方法通过在插入一个项以分散数据时移动哈希表中的条目来减少检索时间。这会增加插入时间,但假定读取的内容多于插入的内容。还有一些方法尝试将不同的碰撞条目分支出来,以便将条目聚集到一个特定的点上。
此外,如果需要调整集合的大小,则需要重新刷新所有内容或使用动态哈希方法。
简而言之,根据您使用的哈希代码,您可能需要实现自己的冲突解决方法。如果您不将它们存储在集合中,那么您可能可以使用一个哈希函数,该函数只在非常大的范围内生成哈希代码。如果是这样,您可以根据您的内存问题确定容器比需要的大(当然,越大越好)。
以下是一些链接,如果您更感兴趣:
维基百科上的合并散列
维基百科还总结了各种冲突解决方法:
THARP的"文件组织与处理"也广泛地涵盖了许多冲突解决方法。在我看来,这是一个很好的参考桥接算法。
取决于返回的哈希值的大小。这是一个简单的逻辑,如果您需要基于4个32位整数的散列返回一个32位整数,就会发生冲突。
我赞成钻头操作。例如,以下C伪代码:
1 2 3 4 5 | int a; int b; int c; int d; int hash = (a & 0xF000F000) | (b & 0x0F000F00) | (c & 0x00F000F0 | (d & 0x000F000F); |
号
这样的系统也可以为浮点工作,如果您只是将它们作为位值,而不是实际表示浮点值,也许更好。
对于弦乐,我几乎不知道。