简洁版本:对于作为无序项字典实现的多重集,最好的哈希算法是什么?
我正在尝试对作为字典实现的不可变多重集(在其他语言中是一个包或多重集:就像一个数学集,除了它可以容纳多个元素)进行散列。我创建了标准库类的子类collections.Counter
,类似于这里的建议:Python 可哈希字典 https://stackoverflow.com/questions/1151658/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 https://github.com/jonashaag/cpython/blob/master/Include/tupleobject.h(在页面中搜索“哈希”一词)——但我几乎不知道足够的 C 语言来阅读它。
想法?建议?谢谢。
(
If you're wondering why I'm messing around with trying to hash a multiset: The input data for my problem are sets of multisets, and within each set of multisets, each multiset must be unique. I'm working on a deadline and I'm not an experienced coder, so I wanted to avoid inventing new algorithms where possible. It seems like the most Pythonic way to make sure I have unique of a bunch of things is to put them in a
set()
, but the things must be hashable.)
我从评论中收集到的内容
@marcin 和 @senderle 给出了几乎相同的答案:使用hash(frozenset(self.items()))
。这是有道理的,因为items()“视图”是类似集合的 http://docs.python.org/py3k/library/stdtypes.html#dictionary-view-objects。 @marcin 是第一个,但我给了 @senderle 复选标记,因为对不同解决方案的 big-O 运行时间进行了很好的研究。 @marcin 还提醒我包括一个__eq__ method http://docs.python.org/py3k/reference/datamodel.html#object.__hash__——但是继承自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