Hashing an immutable dictionary in Python
短版本:对于实现为无序项字典的多集,什么是最好的哈希算法?
我试图散列一个不可变的多集(在其他语言中是一个包或多集:就像一个数学集,除了它可以容纳多个元素之外)作为字典实现。我已经创建了标准库类
1 2 3 4 | class FrozenCounter(collections.Counter): # ... def __hash__(self): return hash(tuple(sorted(self.items()))) |
创建完整的项目元组需要占用大量的内存(例如,相对于使用生成器),散列将发生在应用程序中一个非常占用内存的部分。更重要的是,我的字典键(多集元素)可能无法订购。
我正在考虑使用这个算法:
1 2 | 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来读它。
思想?建议?谢谢。
(如果你想知道我为什么要搞混一个多重集:我问题的输入数据是一组多重集,在每个多重集内,每个多重集都必须是唯一的。我在工作的最后期限,我不是一个经验丰富的程序员,所以我想避免发明新的算法在可能的情况下。要确保我有一堆独特的东西,最像是Python的方法是把它们放在一个
我从评论中收集到的信息
@marcin和@senderle给出了几乎相同的答案:使用
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
因为字典是不可变的,所以可以在创建字典时创建哈希,并直接返回它。我的建议是从
提供一个明确的例子:
1 2 3 4 5 6 | >>>> frozenset(Counter([1, 1, 1, 2, 3, 3, 4]).iteritems()) frozenset([(3, 2), (1, 3), (4, 1), (2, 1)]) >>>> hash(frozenset(Counter([1, 1, 1, 2, 3, 3, 4]).iteritems())) -3071743570178645657 >>>> hash(frozenset(Counter([1, 1, 1, 2, 3, 4]).iteritems())) -6559486438209652990 |
为了解释为什么我更喜欢
你考虑过
您也可以将元素散列在一起XOR,但坦率地说,我不知道这有多有效(您会有很多冲突吗?).说到碰撞,你不需要实现
或者,与我这里的回答类似,