简短版本:作为无序项字典实现的多重集的最佳散列算法是什么?
我正在尝试散列一个不可变的多重集(在其他语言中是一个包或多重集:就像一个数学集,除了它可以容纳多个元素)作为字典实现。我创建了标准库类的一个子类collections.Counter
,类似于这里的建议:Python hashable dicts,它推荐了一个像这样的哈希函数:
class FrozenCounter(collections.Counter):
# ...
def __hash__(self):
return hash(tuple(sorted(self.items())))
创建项目的完整元组会占用大量内存(例如,相对于使用生成器),并且在我的应用程序的内存非常密集的部分会发生散列。更重要的是,我的字典键(多集元素)可能无法订购。
我正在考虑使用这个算法:
def __hash__(self):
return functools.reduce(lambda a, b: a ^ b, self.items(), 0)
我认为使用按位异或意味着顺序对哈希值无关紧要,这与元组的哈希不同?我想我可以在我的数据的无序元组流上半实现 Python 元组哈希算法。请参阅https://github.com/jonashaag/cpython/blob/master/Include/tupleobject.h(在页面中搜索“哈希”一词)——但我几乎不知道足够的 C 来阅读它。
想法?建议?谢谢。
(如果您想知道我为什么要尝试散列一个多重集:我的问题的输入数据是多重集的集合,并且在每组多重集中,每个多重集必须是唯一的。我正在截止日期前工作而且我不是经验丰富的编码员,所以我想尽可能避免发明新算法。似乎最 Pythonic 的方法来确保我拥有一堆东西中的独特性,就是把它们放在 a 中
set()
,但这些东西必须是可散列的。)
我从评论中收集到的
@marcin 和 @senderle 都给出了几乎相同的答案: use hash(frozenset(self.items()))
。这是有道理的,因为items()
“视图”是 set-like。@marcin 是第一个,但我给@senderle 打了勾,因为对不同解决方案的 big-O 运行时间进行了很好的研究。@marcin 还提醒我包含一种__eq__
方法——但继承自的方法dict
可以正常工作。这就是我实现一切的方式——欢迎基于此代码的进一步评论和建议:
class FrozenCounter(collections.Counter):
# Edit: A previous version of this code included a __slots__ definition.
# But, from the Python documentation: "When inheriting from a class without
# __slots__, the __dict__ attribute of that class will always be accessible,
# so a __slots__ definition in the subclass is meaningless."
# http://docs.python.org/py3k/reference/datamodel.html#notes-on-using-slots
# ...
def __hash__(self):
"Implements hash(self) -> int"
if not hasattr(self, '_hash'):
self._hash = hash(frozenset(self.items()))
return self._hash