代码之家  ›  专栏  ›  技术社区  ›  mtasic85 Ed Heal

哈希函数有问题:哈希(1)==哈希(1.0)

  •  1
  • mtasic85 Ed Heal  · 技术社区  · 17 年前

    我有一个例子 dict 具有 int S float S string 作为钥匙,但问题在于 a 作为 int 和 b 作为 浮动 和 float(a) == b ,那么它们的散列值是相同的,这是我不想得到的,因为在这种情况下,我需要唯一的散列值才能得到相应的值。

    例子:

    d = {1:'1', 1.0:'1.0', '1':1, '1.0':1.0}
    d[1] == '1.0'
    d[1.0] == '1.0'
    d['1'] == 1
    d['1.0'] == 1.0
    

    我需要的是:

    d = {1:'1', 1.0:'1.0', '1':1, '1.0':1.0}
    d[1] == '1'
    d[1.0] == '1.0'
    d['1'] == 1
    d['1.0'] == 1.0
    
    4 回复  |  直到 16 年前
        1
  •  7
  •   Mike Graham    16 年前

    自从 1 == 1.0 如果是这样的话,它将可怕地破坏哈希的语义(因此,dict和set)。 hash(1) != hash(1.0) . 更一般地说,必须始终这样 x == y 暗示 hash(x) == hash(y) 为了所有 x 和 y (当然,没有条件要求保留反向含义)。

    所以你的字典 d 只有三个条目,因为在dict display中编写的第二个条目会覆盖第一个条目。如果需要强制只在相同类型之间保持相等(通常与数字不同),则需要一个包装器,例如:

    class W(object):
    
      def __init__(self, x):
        self.x = x
        self.t = type(x)
    
      def __eq__(self, other):
        t = type(other)
        if t != type(self):
          return False
        return self.x == other.x and self.t == other.t
    
      def __hash__(self):
        return hash(self.x) ^ hash(self.t)
    
      def __getattr__(self, name):
        return getattr(self.x, name)
    

    根据您的具体需要,您可能还希望覆盖其他方法(其他比较方法,如 __cmp__ 或 __le__ ,算术的, __repr__ 等等)。无论如何,这将允许您构建一个与所需内容类似的dict,仅用作键。 W(1) 而不是光秃秃的 1 和 W(1.0) 而不是光秃秃的 1.0 (您可能不需要对非数字进行换行,但如果您选择这样做不会造成任何伤害,而且如果所有密钥都被平均换行,则可以很容易地从您的dict中进行检索)。

        2
  •  6
  •   Martin Beckett    17 年前

    使用float作为字典键是“不明智的”,不可能保证两个float的计算值相同。

    最好的方法是将键相乘到预定的小数位数,并使用该整数作为键。

    编辑:很抱歉,您似乎不想使用实数键的dict,您只想根据输入类型格式化输出?

        3
  •  2
  •   Adam Nelson    17 年前

    如果你真的只需要知道区别,也许可以做一些黑客的事情,比如:

    x = '1'
    y = 1
    
    hash(type(x) + x) != hash(type(y) + y)
    
        4
  •  1
  •   Mark Rushakoff    17 年前

    这不能解决你的问题,但从 Python 2.6's number documentation :

    实现人员应该小心地使相等的数字相等,并将它们散列为相同的值。

    你能不能把浮点数设为1.00001,或者类似的?