1. 程式人生 > >set或dict字典去重本質原理

set或dict字典去重本質原理

去重本質原理

  • __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策略決定存留。