首页 > 解决方案 > 类的两个实例相等但哈希码不同

问题描述

我正在研究空间项目中的几何,我有不同的几何实体,其中 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))

标签: python

解决方案


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

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

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

点可视化

所以aandb应该有相同的哈希码并且bandc应该有相同的哈希码,但不是aand c?这怎么可能?

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

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


推荐阅读