set或dict字典去重本质原理

本文深入探讨了去重的本质原理及实例hash的工作机制,详细解释了如何通过正确的hash算法策略来减少hash冲突,并展示了如何利用__hash__和__eq__属性实现有效的数据去重。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

去重本质原理

  • __hash__值不等时,肯定不能去重
  • __hash__值相等时,称hash冲突,冲突后得看__eq__是否相等,若相等则去重

实例hash工作原理

  • 在__hash__返回必须为整数
  • __hash__需自行定义hash的内容

任意实例hash为同一整数

  • 说明hash返回值是由__hash__控制
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __hash__(self):
        return 5000000

a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
运行结果:
5000000
5000000

不同实例hash值可能相等

  • 说明hash算法决定实例hash值是否相等
  • 举例:不同的坐标点,hash算法采用x+y的值,因此只要x+y相等,则hash值即相等
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __hash__(self):
        return self.x + self.y

a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
运行结果:
3
3

正确hash算法策略

  • 要避免hash冲突,首先要尽可能的算法要不一致
  • 坐标点通过构建元组(x,y),对元组进行hash,因此只要x和y任意一个不相等,则hash值就不等
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __hash__(self):
        return hash((self.x,self.y))

a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
运行结果:
3713081631934410656
3713082714465905806

验证集合__hash__不等去重与否

hash值不等时,肯定不能去重

在字典和集合,hash值相当于门牌号码,都不在一个房间里,肯定不能去重,去重的前提时,在一个房间里,是否为同一个值,如果时同一个值时,才能去重,不是同一个值时,不能去重,因此又引入__eq__判断是否相等的特殊属性。

class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __hash__(self):
        return hash((self.x,self.y))

    def __repr__(self):
        return "Point({},{})".format(self.x,self.y)

a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
print({a,b})
运行结果:
3713081631934410656
3713082714465905806
{Point(1,2), Point(2,1)}

hash值相等时,能否去重

  • hash值相同时,说明在同一个房间内了,能否去重要根据__eq__是否为同一个数据了
  • 如下实例,hash值相等,但是没有去重,因为不支持判断是否相等即eq属性
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __hash__(self):
        return self.x+self.y

    def __repr__(self):
        return "Point({},{})".format(self.x,self.y)

a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
print({a,b})
运行结果:
3
3
{Point(2,1), Point(1,2)}

hash值相等,eq策略值不等不去重

  • 当eq值不等时,说明同一个房间放着两个不同数据,当然不能去重
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __hash__(self):
        return self.x+self.y

    def __repr__(self):
        return "Point({},{})".format(self.x,self.y)

    def __eq__(self,other):
        return self.x == other.y and self.y == other.y

a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
print({a,b})
运行结果:
3
3
{Point(2,1), Point(1,2)}

hash值相等,eq策略值相等时,去重

  • 当eq策略值相等时,说明就是同一个值了
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __hash__(self):
        return self.x+self.y

    def __repr__(self):
        return "Point({},{})".format(self.x,self.y)

    def __eq__(self,other):
        return self.x == other.y and self.y == other.x

a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
print({a,b})
运行结果:
3
3
{Point(1,2)}

江湖案例

一山不容二虎,eq的策略是什么?头把交椅,若一个山上有两个都想坐头把交椅,则必须去重,只能留一个,相当于宋江火并王伦。若一个当头领,一个当军师,此时二者都可以留。因此要根据eq策略决定存留。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值