短版:作为无序项字典实现的多重集最佳哈希算法是什么?
我正在尝试对作为字典实现的不可变多重集(在其他语言中称为袋或多重集:类似于数学集合,但可以容纳多个相同元素)进行哈希。我已经创建了一个标准库类collections.Counter的子类,类似于这里的建议:Python hashable dicts,该建议推荐使用以下哈希函数:
创建完整的元组需要占用大量内存(相对于使用生成器而言),并且哈希将在我应用程序中极耗费内存的部分发生。更重要的是,我的字典键(多重集合元素)可能无法排序。
我正在考虑使用这个算法:
我想使用位异或运算符意味着哈希值的顺序不重要,不像哈希元组一样? 我可以在数据的无序元组流上半实现Python元组哈希算法。请参见https://github.com/jonashaag/cpython/blob/master/Include/tupleobject.h(在页面中搜索单词'hash')-但我几乎不了解足够的C语言来阅读它。
有什么想法?建议?谢谢。
(如果您想知道为什么我要尝试对多重集进行哈希:我的问题的输入数据是多重集的集合,并且在每个多重集的集合中,每个多重集必须是唯一的。我正在按期限工作,而且我不是经验丰富的编码人员,因此我希望尽可能避免发明新的算法。似乎确保我拥有一堆独特的东西的最Pythonic方法是将它们放入
从评论中我所收集到的
我正在尝试对作为字典实现的不可变多重集(在其他语言中称为袋或多重集:类似于数学集合,但可以容纳多个相同元素)进行哈希。我已经创建了一个标准库类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(在页面中搜索单词'hash')-但我几乎不了解足够的C语言来阅读它。
有什么想法?建议?谢谢。
(如果您想知道为什么我要尝试对多重集进行哈希:我的问题的输入数据是多重集的集合,并且在每个多重集的集合中,每个多重集必须是唯一的。我正在按期限工作,而且我不是经验丰富的编码人员,因此我希望尽可能避免发明新的算法。似乎确保我拥有一堆独特的东西的最Pythonic方法是将它们放入
set()
中,但这些东西必须是可哈希的。)从评论中我所收集到的
@marcin和@senderle给出了几乎相同的答案:使用hash(frozenset(self.items()))
。这是有道理的,因为items()
“视图”类似于集合。虽然@marcin先回答,但我选择了@senderle,因为他对不同解决方案的大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
tuple
占用了很多内存吗?它只是指向字典中每个项目的“指针”,而不是创建一个副本。 - agf