【问题标题】:Alter the hash function of a dictionary改变字典的散列函数
【发布时间】:2016-09-03 09:35:18
【问题描述】:

根据question,我们知道两个不同的字典,例如dict_1dict_2,使用完全相同的哈希函数。

有没有办法改变字典使用的哈希函数?否定答案也接受!

【问题讨论】:

  • 嘿,格式不错!我不知道您可以在帖子中使用标签或子放置文本...
  • 在有人教我@linusg 之前也是如此!使用不带点的 [...tag: ...Python] 并将文本括在 sub 和 sup 标签中以获得结果。点击我的问题上的编辑,看看这是如何完成的!
  • 我缩小了@ReutSharabani 的问题范围。
  • 请问:为什么要改变哈希函数?
  • @TadhgMcDonald-Jensen 当然。在我编辑之前试图解释这一点。现在我不想再次编辑并返回。因为这个原因我想要那个:stackoverflow.com/questions/37089971/…

标签: python python-2.7 dictionary hash locality-sensitive-hash


【解决方案1】:

您无法更改哈希函数 - dict 将在它应该插入的键上调用 hash,仅此而已。

但是,您可以包装密钥以提供不同的__hash____eq__-方法。

class MyHash(object):
     def __init__(self, v):
         self._v = v

     def __hash__(self):
         return hash(self._v) * -1

     def __eq__(self, other):
         return self._v == other._v

如果这实际上有助于解决您最初的问题/问题,我怀疑,似乎一个自定义的基于数组/列表的数据结构可能是答案。或者不。

【讨论】:

  • “不需要我实现__eq__。”是什么意思?
  • 当我执行 my_dict = {} ; my_dict[MyHash("foo")] = 4 ; print(my_dict[MyHash("foo")]) 时,我得到一个 KeyError,我认为您仍然需要实现 __eq__ 才能使其正常工作。
  • @TadhgMcDonald-Jensen 我的评论实际上是指 _v 的相等性仍然匹配 __hash__ 的简单修改,但这并没有改变我必须转发到原始__eq__。感谢您指出这一点。
【解决方案2】:

这是列表列表顶部的“哈希表”,其中每个哈希表对象都与特定的哈希函数相关联。

class HashTable(object):
    def __init__(self, hash_function, size=256):
        self.hash_function = hash_function
        self.buckets = [list() for i in range(size)]
        self.size = size

    def __getitem__(self, key):
        hash_value = self.hash_function(key) % self.size
        bucket = self.buckets[hash_value]
        for stored_key, stored_value in bucket:
            if stored_key == key:
                return stored_value
        raise KeyError(key)


    def __setitem__(self, key, value):
        hash_value = self.hash_function(key) % self.size
        bucket = self.buckets[hash_value]
        i = 0
        found = False
        for stored_key, stored_value in bucket:
            if stored_key == key:
                 found = True
                 break
            i += 1
        if found:
            bucket[i] = (key, value)
        else:
            bucket.append((key, value))

您的应用程序的其余部分仍然可以看到底层的存储桶列表。您的应用程序可能需要将额外的元数据与每个存储桶关联,但这就像为存储桶列表的元素定义一个新类而不是普通列表一样简单。

【讨论】:

  • 为什么会遭到反对?我要投票,因为这里没有理由。 :)
  • 这可能是因为我最初忘记了在 __setitem__ for 循环中增加 i,我花了 40 秒才注意到,或者我没有评论一行的代码。类定义是不言自明的,还是我应该记录更多?
  • 您的答案,您的选择。 :) 一篇好文章的长度不是必须的。比如我的best answer一开始很小,但后来我想扩大它,值得!我的best question 很短(相对而言)。
【解决方案3】:

我认为您想要的是一种创建存储桶的方法。基于此,我建议 collections.defaultdict 使用 set 初始化程序作为“桶”(取决于您使用它的目的)。

这是一个示例:

#!/usr/bin/env python

from collections import defaultdict
from itertools import combinations

d = defaultdict(set)

strs = ["str", "abc", "rts"]
for s in strs:
    d[hash(s)].add(s)
    d[hash(''.join(reversed(s)))].add(s)

for combination in combinations(d.values(), r=2):
    matches = combination[0] & combination[1]
    if len(matches) > 1:
        print matches

# output: set(['str', 'rts'])

这里结束在同一个桶中的两个字符串非常很可能相同。我通过使用 reverse 函数并使用字符串创建了哈希冲突,并且它作为值是反向的。

请注意,该集合将使用完全比较,但应该非常快。

不要在不耗尽集合的情况下散列太多值。

【讨论】:

  • 嘿,您取消删除了您的答案,这不是通知。感谢您提供替代解决方案!
猜你喜欢
  • 2012-11-10
  • 2019-12-12
  • 2011-08-18
  • 2020-09-05
  • 2012-11-09
  • 2010-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多