【问题标题】:Two instances of class are equal but different hash code类的两个实例相等但哈希码不同
【发布时间】:2020-06-22 14:34:20
【问题描述】:

我正在研究空间项目中的几何,我有不同的几何实体,其中包括 Point.有时两个点相等,但由于计算导致的小数值误差,例如 1 和 1.0000000001,所以我实现了 __eq__ 方法和 math.isclose() 函数来解决这个问题。

class Point(object):

    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def __eq__(self, other):
        if isinstance(other, Point):
            equal_x = math.isclose(other.x, self.x, rel_tol=5e-3, abs_tol=1e-5)
            equal_y = math.isclose(other.y, self.y, rel_tol=5e-3, abs_tol=1e-5)
            equal_z = math.isclose(other.z, self.z, rel_tol=5e-3, abs_tol=1e-5)
            if equal_x and equal_y and equal_z:
                return True

        return False   

在使用集合和字典时,如何实现__hash__ 方法以使这两个对象相等?

最终目标是使用以下函数来“唯一化”此类对象的列表并删除重复项:

def f12(seq):
    # from Raymond Hettinger
    # https://twitter.com/raymondh/status/944125570534621185
    return list(dict.fromkeys(seq))

【问题讨论】:

  • __hash__() 的绝对要求是它为__eq__() 所说的相等的对象返回相等的值。因此,请考虑您的类中名为X 的某个对象,它具有特定的哈希码。向每个坐标添加一点点,以便它们仍然通过 isclose() 测试:哈希 必须 保持不变。再多加一点,hash 一定还是一样的,以此类推。 唯一 __hash__() 实现与您的__eq__() 一致是返回一个常量 - 这当然会破坏集合或字典的效率。
  • __eq__ 应该是可传递的,但你的不是。 x == yy == z 可能没有 x == z 为真。
  • Hash 应该是一种快速计算的方法,它为“相同”的事物提供相同的结果(用引号引起来,因为您可以以不同的方式定义它)。最好是“不同”事物的不同结果。 - 最好是这样你甚至可以实现总是返回 1 的哈希,但这不会加快速度。
  • 在您的情况下,请考虑 xyz 采用什么值 - 并相应地划分空间,例如空间中的 1x1x1 框 10x10x10 => 散列可能是 100*round(x)+10*round(y)+round(z) 但正如 chepner 所说,你在这里还有其他问题,我提到的散列的“盒子”将不起作用(1.9(...)95 和 2.0(。 ..)01 在不同的盒子里,但“相等”)

标签: python


【解决方案1】:

不要给你的点一个“无效的”__eq__ 方法,而是给他们一个 isclose 方法,使用你已经拥有的代码,并使用它而不是 == 或者使它们在标准意义上相等将坐标四舍五入。

【讨论】:

  • 感谢您的回答,将数字四舍五入是我正在考虑的解决方案之一。我只是想让舒尔代码不会乱码!
【解决方案2】:

您的 equal 方法存在一般问题。

大多数人会期望以平等的方式传递传递。这意味着当两个点ab 相等并且a 也等于另一个点c 时,那么ac 也应该相等。在您的实施中不一定是这种情况。

想象每个点,在他周围有一个球体,这些点被认为是相等的。下图显示了这个球体(或更好的球体半径的一半),因此重叠意味着点相等:

所以ab 应该有相同的哈希码,bc 应该有相同的哈希码,但ac 不应该有相同的哈希码?这怎么可能?

我建议添加一个额外的方法is_close_to 并在那里实现逻辑。

编辑: @JLPeyret 指出,您可以使用网格并计算与包含该点的网格象限相对应的点的哈希值。在这种情况下,两个邻近点可能接近网格象限的划分,因此分配有不同的哈希值。如果这种概率方法适合您,请查看locality-sensitive hashing

【讨论】:

  • 如果您将其概念化为离散网格,并通过 x,y,z 的rounding 将每个点根据其自身的优点(而不是相对于其他点)分配给网格中的一个单元格,该怎么办?在网格位置上散列。如果 a == b 那么这意味着它们在同一个单元格中。 b==c 表示 c 也在同一个单元格中。
  • @JLPeyret 感谢您的意见,我在答案中添加了一个补充内容。
  • 非常感谢大家的投入,我对这些东西有点陌生,但你给了我很多思考!
猜你喜欢
  • 2012-09-24
  • 2013-04-30
  • 1970-01-01
  • 2011-07-23
  • 2015-02-25
  • 2015-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多