Python3 集合(Set):去重神器,还有你不知道的用法
我是陈默,一个正拼命上岸的码农。
问你一个问题。
一个列表里有 1000 个元素,你怎么快速判断某个值存不存在?
用 in 遍历列表?可以,但慢。
用集合?一瞬间就搞定。
集合是 Python 里最被低估的数据结构。很多人只知道它能去重,但它的本事远不止于此。
1. 创建集合:不重复的盒子
集合用花括号 {} 表示,元素之间用逗号隔开。
# 创建集合colors = {"红", "绿", "蓝", "红", "绿"}print(colors) # 输出: {'红', '绿', '蓝'}(重复的自动去掉了)# 从列表创建集合nums = set([1, 2, 3, 2, 1, 4])print(nums) # 输出: {1, 2, 3, 4}# 空集合(注意:不能用 {},那是空字典)empty = set()print(type(empty)) # 输出: <class 'set'>print(type({})) # 输出: <class 'dict'>
{} 创建的是空字典,不是空集合。空集合必须用 set()。
这是第二个坑。第一个是元组的单元素逗号。记住这两个,面试能加分。
集合的两个特点
s = {3, 1, 2}print(s[0]) # 报错!TypeError: 'set' object is not subscriptable
2. 集合的基本操作
添加元素
fruits = {"苹果", "香蕉"}# add():添加一个元素fruits.add("橙子")print(fruits) # 输出: {'苹果', '香蕉', '橙子'}# 添加重复的?没效果fruits.add("苹果")print(fruits) # 输出: {'苹果', '香蕉', '橙子'}(没有变化)
删除元素
fruits = {"苹果", "香蕉", "橙子"}# remove():删除指定元素(不存在会报错)fruits.remove("香蕉")print(fruits) # 输出: {'苹果', '橙子'}# discard():删除指定元素(不存在不报错)fruits.discard("西瓜") # 没有西瓜,但不报错print(fruits) # 输出: {'苹果', '橙子'}# pop():随机删除一个元素item = fruits.pop()print(f"删掉了:{item}")print(fruits) # 剩下的元素# clear():清空集合fruits.clear()print(fruits) # 输出: set()
remove() 和 discard() 的区别:一个会报错,一个不会。
不确定元素存不存在的时候,用 discard() 更安全。
3. 集合运算:这才是集合的真正实力
数学里的集合运算——交集、并集、差集——Python 全都支持。
交集:两个集合都有的
a = {1, 2, 3, 4, 5}b = {3, 4, 5, 6, 7}# 方法一:&print(a & b) # 输出: {3, 4, 5}# 方法二:intersection()print(a.intersection(b)) # 输出: {3, 4, 5}
并集:两个集合所有的(去重)
a = {1, 2, 3, 4, 5}b = {3, 4, 5, 6, 7}# 方法一:|print(a | b) # 输出: {1, 2, 3, 4, 5, 6, 7}# 方法二:union()print(a.union(b)) # 输出: {1, 2, 3, 4, 5, 6, 7}
差集:a 里有但 b 里没有的
a = {1, 2, 3, 4, 5}b = {3, 4, 5, 6, 7}# 方法一:-print(a - b) # 输出: {1, 2}# 方法二:difference()print(a.difference(b)) # 输出: {1, 2}
对称差集:只在其中一个集合里的
a = {1, 2, 3, 4, 5}b = {3, 4, 5, 6, 7}# 方法一:^print(a ^ b) # 输出: {1, 2, 6, 7}# 方法二:symmetric_difference()print(a.symmetric_difference(b)) # 输出: {1, 2, 6, 7}
用运算符更简洁,用方法更易读。看团队习惯。
4. 子集和超集:判断包含关系
a = {1, 2, 3}b = {1, 2, 3, 4, 5}# a 是 b 的子集吗?print(a.issubset(b)) # 输出: True# b 是 a 的超集吗?print(b.issuperset(a)) # 输出: True# 两个集合有没有交集?c = {6, 7, 8}print(a.isdisjoint(c)) # 输出: True(没有交集)print(a.isdisjoint(b)) # 输出: False(有交集)
5. 集合推导式:一行创建集合
和列表、字典一样,集合也有推导式:
# 把列表里的平方值去重nums = [1, -1, 2, -2, 3, -3]squares = {x ** 2for x in nums}print(squares) # 输出: {1, 4, 9}# 只要偶数的平方nums = [1, 2, 3, 4, 5, 6]even_squares = {x ** 2for x in nums if x % 2 == 0}print(even_squares) # 输出: {16, 4, 36}
6. 不可变集合:frozenset
集合本身是可变的,但有时候你需要一个不可变的集合。
# 普通集合s = {1, 2, 3}s.add(4) # 可以修改# 不可变集合fs = frozenset([1, 2, 3])fs.add(4) # 报错!AttributeError: 'frozenset' object has no attribute 'add'
什么时候用 frozenset?
当你需要把集合当字典的键,或者放进另一个集合里的时候:
# 集合不能做字典的键# bad = {{1, 2}: "值"} # 报错!# frozenset 可以good = {frozenset([1, 2]): "值"}print(good[frozenset([1, 2])]) # 输出: 值
7. 集合 vs 列表:什么时候用哪个?
简单判断:
8. 实战:用集合解决实际问题
去重
# 用户访问记录,找出不重复的用户visits = ["user1", "user2", "user1", "user3", "user2", "user4", "user1"]unique_users = set(visits)print(f"总访问:{len(visits)}次")print(f"独立用户:{len(unique_users)}个")print(f"用户列表:{unique_users}")# 输出:# 总访问:7次# 独立用户:4个# 用户列表:{'user1', 'user2', 'user3', 'user4'}
找共同好友
my_friends = {"小明", "小红", "小华", "小刚"}your_friends = {"小红", "小华", "小李", "小王"}# 共同好友common = my_friends & your_friendsprint(f"共同好友:{common}") # 输出: {'小红', '小华'}# 我有但你没有的好友only_mine = my_friends - your_friendsprint(f"只有我认识的:{only_mine}") # 输出: {'小明', '小刚'}# 所有的朋友(去重)all_friends = my_friends | your_friendsprint(f"朋友圈:{all_friends}") # 输出: {'小明', '小红', '小华', '小刚', '小李', '小王'}
找列表里的重复元素
data = [1, 3, 5, 3, 7, 1, 9, 5, 3]# 找出哪些元素重复了duplicates = set()seen = set()for item in data:if item in seen: duplicates.add(item) seen.add(item)print(f"重复的元素:{duplicates}") # 输出: {1, 3, 5}
最后
集合看起来简单,但三个场景离不开它:去重、快速查找、集合运算。
记住三件事:
- 集合运算用符号更简洁:
& 交集、| 并集、- 差集
我的建议:
打开你的编辑器,写一个列表,里面有重复数据。然后试着用集合去重、找交集、找差集。把运算符和方法各写一遍,感受一下哪个更顺手。
学数据结构最好的方式:用真实数据跑一遍。
今天就到这里。
我是陈默,我们下期再见。
如果你觉得这篇文章有帮助,欢迎关注我。我会持续分享 Python 学习的干货。