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策略决定存留。

<think>好的,用户现在想了解Pythonset函数的使用方法和示例。先回顾之前的对话,用户已经询问过set的用法,我给出了详细的回答,包括核心功能、应用场景、方法速查表、注意事项等。现在用户再次提问,可能希望得到更简洁更针对性的信息,者可能有未满足的需求。 首先,检查用户当前的查询是否与之前的问题复。用户提到“参考站内引用”,引用了两个示例,一个是关于集合运算中&和and的区别,另一个是Matlab的set函数。但用户明确指出这些引用仅供参考,不是真实需求,需要参考上一次的问题和回答。所以用户真正的需求仍然是Pythonset函数。 用户可能之前已经阅读过详细回答,但希望得到更直接的步骤示例,者可能有新的疑问。需要确保回答覆盖基础用法、常见操作和示例,同时避免复之前的内容,但可能需要更简洁补充新内容。 需要确定用户可能的疑问点:比如如何创建集合,集合的常见操作,与列表的区别,集合运算的实际应用等。根据之前的回答,用户可能已经了解这些,但可能需要更具体的示例,者实际应用场景的深入说明。 另外,用户提供的引用中提到&和and的区别,可能用户对此有疑问,者希望强调这部分内容。因此,在回答中需要明确区分这两个操作符,给出示例,避免混淆。 还要注意用户可能对集合的性能优势感兴趣,比如成员检测的O(1)时间复杂度,这在处理大数据时非常有用,可以举例说明。 最后,确保回答结构清晰,分点说明,使用代码示例,并自然地融入引用的内容,特别是关于&和and的区别,以解决用户可能的疑惑。</think>### Pythonset函数使用指南(附示例代码) #### 一、基础创建与转换 1. **空集合创建** ```python # 必须用set()创建空集合({}创建的是空字典) empty_set = set() ``` 2. **数据转换**(自动) ```python # 列表转集合 list_to_set = set([2,2,3,5,5]) # {2,3,5} # 字符串转集合 str_to_set = set("apple") # {'a','p','l','e'} # 字典转集合(仅保留键) dict_to_set = set({"A":1,"B":2}) # {'A','B'} ``` #### 二、集合运算关键操作 1. **运算符与逻辑符号区别**(要!) ```python set1 = {1,3,5} set2 = {3,5,7} # &运算符:求交集 print(set1 & set2) # {3,5} [^1] # and逻辑符:返回最后一个真值 print(set1 and set2) # {3,5,7}(非True/False) ``` 2. **三大基础运算** ```python # 并集(合并不复元素) print(set1 | set2) # {1,3,5,7} # 差集(仅在set1中的元素) print(set1 - set2) # {1} # 对称差集(仅出现一次的元素的集合) print(set1 ^ set2) # {1,7} ``` #### 三、典型应用场景示例 1. **电商商品筛选** ```python user1_cart = {"手机", "耳机", "充电宝"} user2_cart = {"耳机", "智能手表", "手机"} # 找出共同购买商品 common_items = user1_cart & user2_cart # {'手机','耳机'} ``` 2. **日志分析** ```python # 统计独立IP访问量 with open("access.log") as f: unique_ips = set(line.split()[0] for line in f) print(f"独立访问IP数:{len(unique_ips)}") ``` 3. **权限系统验证** ```python admin_permissions = {"create", "delete", "modify"} user_permissions = {"view", "modify"} # 检查是否具备危险操作权限 dangerous_ops = admin_permissions - user_permissions # {'create','delete'} ``` #### 四、性能优化对比 | 操作类型 | 列表(100万元素) | 集合(100万元素) | |---------------|------------------|------------------| | 成员检测 | O(n) ~0.008s | O(1) ~0.000001s | | 遍历所有元素 | O(n) | O(n) | | 插入元素 | O(1) | O(1) | | 删除元素 | O(n) | O(1) | #### 五、高频问题解答 **Q1:为什么集合元素不可复?** 集合基于哈希表实现,每个元素的哈希值唯一。当添加复元素时,哈希表会自动覆盖原有值。 **Q2:如何存储可变对象?** 使用`frozenset`包裹可变对象: ```python valid_set = {frozenset([1,2]), frozenset([3,4])} ``` **Q3:集合与字典的关系?** 字典的键集合本质是特殊集合:`dict_keys`类型支持集合运算: ```python d1 = {"A":1,"B":2} d2 = {"B":3,"C":4} print(d1.keys() & d2.keys()) # {'B'} ``` --- ### 进阶技巧 1. **动态过滤数据流** ```python # 实时(适用于IoT设备数据采集) class DataStream: def __init__(self): self.seen = set() def add_data(self, value): if value not in self.seen: self.seen.add(value) return True return False ``` 2. **集合视图操作** ```python # 内存优化技巧(不创建新集合) big_set = set(range(1000000)) subset_view = big_set - {999999} # 不实际删除元素 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值