Python快速入门专业版(三十九):Python集合:去重与集合运算(交集、并集、差集)
目录
- 引
- 一、集合的定义与创建:无序且唯一的元素集合
- 1. 基本创建方式
- 2. 集合的元素限制:不可变类型
- 二、集合的核心功能1:自动去重
- 1. 列表去重的基本实现
- 2. 保持去重后列表顺序(Python 3.7+)
- 3. 实战案例:学生成绩去重
- 三、集合的核心功能2:四大集合运算
- 1. 交集(Intersection):两个集合的共同元素
- 实现方式:
- 2. 并集(Union):两个集合的所有元素(去重)
- 实现方式:
- 3. 差集(Difference):A有但B没有的元素
- 实现方式:
- 4. 对称差集(Symmetric Difference):仅一方有的元素
- 实现方式:
- 集合运算总结表
- 四、集合的常用方法:添加、删除与判断
- 1. 元素添加:`add()`与`update()`
- 2. 元素删除:`remove()`、`discard()`与`pop()`
- 3. 其他常用方法
- 五、综合实战案例
- 案例1:两个列表找共同元素(用交集实现)
- 案例2:列表去重与排序(结合集合与列表方法)
- 案例3:用户标签交集分析(集合运算实战)
- 六、集合的使用场景与注意事项
- 1. 适合使用集合的场景
- 2. 注意事项
- 3. 集合与其他数据结构的对比
- 七、总结
引
集合(set)是Python中一种特殊的数据结构,它以无序、唯一的方式存储元素,类似于数学中的“集合”概念。集合的核心价值在于自动去重和高效的集合运算(如交集、并集、差集),在数据去重、关系判断(如共同元素、独有元素)等场景中应用广泛。
本文将系统讲解集合的定义、创建方式、核心特性,详细演示集合的去重功能、四大集合运算(交集、并集、差集、对称差集)及常用方法,并通过“列表去重”“查找共同元素”等实战案例,帮助你掌握集合的实用技巧。
一、集合的定义与创建:无序且唯一的元素集合
集合是由大括号{}
包裹的元素集合(元素间用逗号分隔),或通过set()
函数创建。其核心特性为:
- 无序性:元素的存储顺序与添加顺序无关,无法通过索引访问(区别于列表、元组)。
- 唯一性:集合中不会出现重复元素,自动过滤重复值(最常用的特性之一)。
- 元素类型限制:元素必须是不可变类型(如整数、字符串、元组),列表、字典等可变类型不能作为集合元素。
1. 基本创建方式
# 1. 用大括号创建集合(元素唯一,自动去重)
s1 = {1, 2, 3, 3, 4} # 重复元素3被自动过滤
print(s1) # 输出:{1, 2, 3, 4}(顺序可能不同,因集合无序)# 2. 创建空集合(必须用set(),不能用{},{}表示空字典)
empty_set = set()
print(type(empty_set)) # 输出:<class 'set'>
print(type({})) # 输出:<class 'dict'>(空字典)# 3. 用set()函数创建(接收可迭代对象,如列表、字符串、元组)
# 列表转集合(自动去重)
list_to_set = set([1, 2, 2, 3])
print(list_to_set) # 输出:{1, 2, 3}# 字符串转集合(按字符拆分,自动去重)
str_to_set = set("python")
print(str_to_set) # 输出:{'p', 'y', 't', 'h', 'o', 'n'}(顺序随机)# 元组转集合
tuple_to_set = set((1, 2, 3, 3))
print(tuple_to_set) # 输出:{1, 2, 3}
2. 集合的元素限制:不可变类型
集合的元素必须是不可变类型,若包含列表、字典等可变类型,会直接抛出TypeError
:
# 错误:列表是可变类型,不能作为集合元素
# invalid_set = {1, [2, 3]} # 错误:TypeError: unhashable type: 'list'# 正确:元组是不可变类型,可作为集合元素
valid_set = {1, (2, 3), "hello"}
print(valid_set) # 输出:{1, 'hello', (2, 3)}
二、集合的核心功能1:自动去重
集合的“唯一性”特性使其成为列表去重的最优工具之一。只需将列表转换为集合,再转回列表,即可快速去除重复元素(注意:转换后列表顺序会改变,因集合无序)。
1. 列表去重的基本实现
# 案例1:简单列表去重
original_list = [1, 2, 2, 3, 3, 3, 4]
# 步骤:列表→集合(去重)→列表(恢复列表类型)
unique_list = list(set(original_list))
print(unique_list) # 输出:[1, 2, 3, 4](顺序可能不同)# 案例2:包含字符串的列表去重
str_list = ["apple", "banana", "apple", "orange", "banana"]
unique_str_list = list(set(str_list))
print(unique_str_list) # 输出:['apple', 'banana', 'orange'](顺序随机)
2. 保持去重后列表顺序(Python 3.7+)
由于集合无序,直接转换会丢失原列表的顺序。若需保持顺序,可结合dict.fromkeys()
(字典键唯一且Python 3.7+保留插入顺序)实现:
original_list = [2, 1, 3, 1, 2, 4]# 方法:利用字典键的唯一性和有序性
# 1. dict.fromkeys(original_list) 生成键为列表元素、值为None的字典(自动去重且保序)
# 2. .keys() 获取字典的键(即去重后的元素,顺序与原列表一致)
# 3. 转换为列表
unique_ordered_list = list(dict.fromkeys(original_list).keys())
print(unique_ordered_list) # 输出:[2, 1, 3, 4](保持原顺序)
3. 实战案例:学生成绩去重
假设需要统计班级学生的独特分数(去除重复分数),用集合可快速实现:
# 班级学生成绩列表(含重复分数)
scores = [85, 90, 85, 95, 90, 80, 85, 95]# 去重并统计独特分数的数量
unique_scores = set(scores)
print(f"所有分数:{scores}")
print(f"独特分数:{unique_scores}")
print(f"独特分数数量:{len(unique_scores)}") # 输出:独特分数数量:4
三、集合的核心功能2:四大集合运算
集合完全模拟了数学中的集合运算,支持交集、并集、差集、对称差集四种核心运算,每种运算都有运算符和方法两种实现方式,运算效率极高(底层基于哈希表)。
假设有两个集合:
# 集合A:数学成绩≥90分的学生ID
A = {101, 102, 103, 104}
# 集合B:语文成绩≥90分的学生ID
B = {103, 104, 105, 106}
1. 交集(Intersection):两个集合的共同元素
定义:同时存在于集合A和集合B中的元素,对应数学中的“A∩BA \cap BA∩B”。
应用场景:查找两个群体的交集(如同时在数学和语文考试中得高分的学生)。
实现方式:
- 运算符:
A & B
- 方法:
A.intersection(B)
(或B.intersection(A)
,结果相同)
# 计算交集:同时在A和B中的学生ID
common_students = A & B
# 或用方法:common_students = A.intersection(B)print(f"数学高分学生:{A}")
print(f"语文高分学生:{B}")
print(f"两科都高分的学生:{common_students}") # 输出:{103, 104}
2. 并集(Union):两个集合的所有元素(去重)
定义:存在于集合A或集合B中的所有元素(自动去重),对应数学中的“A∪BA \cup BA∪B”。
应用场景:合并两个群体并去除重复(如统计数学或语文考试中得高分的所有学生)。
实现方式:
- 运算符:
A | B
- 方法:
A.union(B)
(或B.union(A)
,结果相同)
# 计算并集:数学或语文高分的所有学生ID(去重)
all_excellent_students = A | B
# 或用方法:all_excellent_students = A.union(B)print(f"数学或语文高分的学生:{all_excellent_students}") # 输出:{101, 102, 103, 104, 105, 106}
print(f"总人数:{len(all_excellent_students)}") # 输出:总人数:6
3. 差集(Difference):A有但B没有的元素
定义:存在于集合A中,但不存在于集合B中的元素,对应数学中的“A−BA - BA−B”。
应用场景:查找某个群体独有的元素(如数学高分但语文未得高分的学生)。
实现方式:
- 运算符:
A - B
- 方法:
A.difference(B)
(注意:A-B
与B-A
结果不同)
# 计算A-B:数学高分但语文未高分的学生
math_only_excellent = A - B
# 或用方法:math_only_excellent = A.difference(B)# 计算B-A:语文高分但数学未高分的学生
chinese_only_excellent = B - A
# 或用方法:chinese_only_excellent = B.difference(A)print(f"数学高分但语文未高分:{math_only_excellent}") # 输出:{101, 102}
print(f"语文高分但数学未高分:{chinese_only_excellent}") # 输出:{105, 106}
4. 对称差集(Symmetric Difference):仅一方有的元素
定义:存在于集合A或集合B中,但不同时存在于两个集合中的元素,对应数学中的“AΔBA \Delta BAΔB”(等价于“(A∪B)−(A∩B)(A \cup B) - (A \cap B)(A∪B)−(A∩B)”)。
应用场景:查找两个群体的“独有元素合集”(如仅数学高分或仅语文高分的学生)。
实现方式:
- 运算符:
A ^ B
- 方法:
A.symmetric_difference(B)
(或B.symmetric_difference(A)
,结果相同)
# 计算对称差集:仅数学高分或仅语文高分的学生
only_one_excellent = A ^ B
# 或用方法:only_one_excellent = A.symmetric_difference(B)print(f"仅一科高分的学生:{only_one_excellent}") # 输出:{101, 102, 105, 106}
# 验证:对称差集 = 并集 - 交集
verify = (A | B) - (A & B)
print(f"验证结果(并集-交集):{verify}") # 输出:{101, 102, 105, 106}
集合运算总结表
运算类型 | 运算符 | 方法 | 含义 | 案例结果(A={101,102,103,104}, B={103,104,105,106}) |
---|---|---|---|---|
交集 | A & B | A.intersection(B) | A和B的共同元素 | {103, 104} |
并集 | A | B | A或B的所有元素(去重) | {101,102,103,104,105,106} |
差集(A-B) | A - B | A.difference(B) | A有但B没有的元素 | {101, 102} |
对称差集 | A ^ B | A.symmetric_difference(B) | 仅一方有的元素 | {101,102,105,106} |
四、集合的常用方法:添加、删除与判断
集合支持一系列实用方法,用于添加元素、删除元素、判断元素关系等,进一步扩展了集合的功能。
1. 元素添加:add()
与update()
s.add(x)
:向集合中添加单个元素(若元素已存在,不做任何操作)。s.update(iterable)
:向集合中批量添加元素(接收可迭代对象,如列表、元组、集合,自动去重)。
s = {1, 2, 3}# 1. 添加单个元素
s.add(4)
print(s) # 输出:{1, 2, 3, 4}
s.add(3) # 添加已存在的元素,无变化
print(s) # 输出:{1, 2, 3, 4}# 2. 批量添加元素(从列表添加)
s.update([4, 5, 6]) # 4已存在,自动去重
print(s) # 输出:{1, 2, 3, 4, 5, 6}# 3. 批量添加元素(从集合添加)
s.update({6, 7, 8})
print(s) # 输出:{1, 2, 3, 4, 5, 6, 7, 8}
2. 元素删除:remove()
、discard()
与pop()
s.remove(x)
:删除集合中的元素x
,若x
不存在,抛出KeyError
。s.discard(x)
:删除集合中的元素x
,若x
不存在,不报错(推荐使用,更安全)。s.pop()
:随机删除集合中的一个元素并返回该元素(因集合无序,无法指定删除位置)。
s = {1, 2, 3, 4, 5}# 1. remove():删除存在的元素
s.remove(3)
print(s) # 输出:{1, 2, 4, 5}
# s.remove(6) # 错误:KeyError: 6(元素不存在)# 2. discard():删除存在的元素
s.discard(4)
print(s) # 输出:{1, 2, 5}
# 删除不存在的元素,无报错
s.discard(6)
print(s) # 输出:{1, 2, 5}(无变化)# 3. pop():随机删除一个元素
deleted = s.pop()
print(f"删除的元素:{deleted}") # 输出:删除的元素:1(随机,可能不同)
print(f"删除后集合:{s}") # 输出:删除后集合:{2, 5}
3. 其他常用方法
s.clear()
:清空集合中的所有元素,使集合变为空集。len(s)
:获取集合中元素的个数。x in s
:判断元素x
是否在集合s
中(返回布尔值)。s.isdisjoint(t)
:判断两个集合是否“无交集”(无共同元素返回True
,否则返回False
)。
s = {1, 2, 3}
t = {4, 5, 6}# 清空集合
s.clear()
print(s) # 输出:set()(空集)# 重新赋值
s = {1, 2, 3}# 获取元素个数
print(len(s)) # 输出:3# 判断元素是否存在
print(2 in s) # 输出:True
print(4 in s) # 输出:False# 判断两个集合是否无交集
print(s.isdisjoint(t)) # 输出:True(s和t无共同元素)
print(s.isdisjoint({3, 4})) # 输出:False(s和{3,4}有共同元素3)
五、综合实战案例
案例1:两个列表找共同元素(用交集实现)
需求:给定两个列表,找出它们的共同元素(去重),要求高效实现。
def find_common_elements(list1, list2):"""找出两个列表的共同元素(去重)参数:list1: 第一个列表list2: 第二个列表返回:共同元素组成的列表(去重)"""# 步骤:列表→集合(去重)→交集(找共同元素)→列表(返回结果)set1 = set(list1)set2 = set(list2)common_set = set1 & set2 # 或 set1.intersection(set2)return list(common_set)# 测试
list_a = [1, 2, 3, 4, 5, 2, 3]
list_b = [3, 4, 5, 6, 7, 5, 6]
common = find_common_elements(list_a, list_b)
print(f"列表A:{list_a}print(f"列表A:{list_a}")
print(f"列表B:{list_b}")
print(f"共同元素(去重):{common}") # 输出:共同元素(去重):[3, 4, 5](顺序可能不同)
解析:
- 先将两个列表转换为集合,利用集合的“唯一性”自动去重(如
list_a
中的重复元素2
、3
被过滤)。 - 通过交集运算(
set1 & set2
)快速找到共同元素,效率远高于“双重循环遍历列表对比”(尤其在数据量大时)。 - 最后将结果转换为列表,符合日常使用习惯。
案例2:列表去重与排序(结合集合与列表方法)
需求:对包含重复元素的列表去重,并按升序排序。
def deduplicate_and_sort(lst):"""列表去重并按升序排序参数:lst - 待处理的列表返回:去重且排序后的列表"""# 步骤:去重(列表→集合)→排序(集合→列表→sort())unique_set = set(lst) # 去重unique_list = list(unique_set) # 转换为列表unique_list.sort() # 升序排序return unique_list# 测试
original = [5, 2, 8, 2, 3, 5, 1, 8]
result = deduplicate_and_sort(original)
print(f"原始列表:{original}")
print(f"去重排序后:{result}") # 输出:去重排序后:[1, 2, 3, 5, 8]
优化:若需保持原列表的“首次出现顺序”并去重排序,可结合dict.fromkeys()
:
def deduplicate_preserve_order_and_sort(lst):# 保持首次出现顺序去重→排序ordered_unique = list(dict.fromkeys(lst).keys()) # 保序去重ordered_unique.sort() # 排序return ordered_unique# 测试
original = [5, 2, 8, 2, 3, 5, 1, 8]
result = deduplicate_preserve_order_and_sort(original)
print(f"保序去重排序后:{result}") # 输出:保序去重排序后:[1, 2, 3, 5, 8]
案例3:用户标签交集分析(集合运算实战)
需求:分析两个用户的兴趣标签,找出共同兴趣、独有兴趣,并统计兴趣重合度。
def analyze_user_tags(user1_tags, user2_tags):"""分析两个用户的标签交集、差集及重合度参数:user1_tags: 用户1的标签列表user2_tags: 用户2的标签列表"""# 转换为集合(去重)set1 = set(user1_tags)set2 = set(user2_tags)# 计算各类集合common_tags = set1 & set2 # 共同标签(交集)user1_only = set1 - set2 # 用户1独有标签(差集)user2_only = set2 - set1 # 用户2独有标签(差集)all_tags = set1 | set2 # 所有标签(并集)# 计算重合度(共同标签数 / 总标签数,保留2位小数)overlap_ratio = len(common_tags) / len(all_tags) if len(all_tags) > 0 else 0.0# 输出结果print("=" * 50)print("用户标签分析结果")print("=" * 50)print(f"用户1标签:{user1_tags}")print(f"用户2标签:{user2_tags}")print(f"\n共同兴趣标签:{common_tags}(共{len(common_tags)}个)")print(f"用户1独有标签:{user1_only}(共{len(user1_only)}个)")print(f"用户2独有标签:{user2_only}(共{len(user2_only)}个)")print(f"兴趣重合度:{overlap_ratio:.2f}({len(common_tags)}/{len(all_tags)})")print("=" * 50)# 测试数据
user1 = ["篮球", "音乐", "电影", "游戏", "音乐", "篮球"] # 含重复标签
user2 = ["电影", "阅读", "音乐", "旅行", "阅读"] # 含重复标签
analyze_user_tags(user1, user2)
输出结果:
==================================================
用户标签分析结果
==================================================
用户1标签:['篮球', '音乐', '电影', '游戏', '音乐', '篮球']
用户2标签:['电影', '阅读', '音乐', '旅行', '阅读']共同兴趣标签:{'电影', '音乐'}(共2个)
用户1独有标签:{'篮球', '游戏'}(共2个)
用户2独有标签:{'阅读', '旅行'}(共2个)
兴趣重合度:0.33(2/6)
==================================================
解析:
- 先将用户标签列表转换为集合,自动去除重复标签(如用户1的重复“篮球”“音乐”)。
- 通过交集、差集运算清晰区分“共同兴趣”“独有兴趣”,为用户画像、兴趣推荐提供数据支持。
- 计算“兴趣重合度”(共同标签数/总标签数),量化两个用户的兴趣相似度。
六、集合的使用场景与注意事项
1. 适合使用集合的场景
- 数据去重:快速去除列表、元组中的重复元素(核心场景)。
- 关系判断:查找两个数据集的共同元素(交集)、独有元素(差集)、合并元素(并集)。
- 成员检测:判断元素是否存在于集合中(
x in set
,效率高于x in list
,尤其数据量大时)。 - 无序唯一数据存储:存储无需保持顺序但需保证唯一性的数据(如用户ID、标签列表)。
2. 注意事项
- 无序性:集合无法通过索引访问元素,若需按顺序操作,需先转换为列表(
list(set)
)。 - 元素类型限制:元素必须是不可变类型(整数、字符串、元组),列表、字典等可变类型不能作为集合元素。
- 空集合创建:必须用
set()
创建空集合,{}
表示空字典,而非空集合。 - 集合运算的返回值:集合运算(如
A & B
、A | B
)返回新集合,不会修改原集合。
3. 集合与其他数据结构的对比
数据结构 | 核心特性 | 适用场景 |
---|---|---|
集合(set) | 无序、唯一、支持集合运算 | 去重、关系判断、成员检测 |
列表(list) | 有序、可重复、可修改 | 存储有序动态数据(如待办事项) |
元组(tuple) | 有序、可重复、不可修改 | 存储固定结构数据(如坐标、配置) |
字典(dict) | 键值对、无序(3.7+有序) | 存储关联数据(如用户信息、映射关系) |
七、总结
集合是Python中极具特色的数据结构,其核心价值在于“自动去重”和“高效集合运算”,通过本文的学习,可总结出以下要点:
-
核心特性:
- 无序性:无法通过索引访问,元素存储顺序与添加顺序无关。
- 唯一性:自动过滤重复元素,适合去重场景。
- 不可变元素:元素必须是不可变类型(如整数、字符串、元组)。
-
核心功能:
- 去重:通过
list(set(lst))
快速去除列表重复元素。 - 集合运算:交集(
&
)、并集(|
)、差集(-
)、对称差集(^
),高效处理数据关系。 - 常用方法:
add()
(添加元素)、discard()
(安全删除)、clear()
(清空)等。
- 去重:通过
-
实战技巧:
- 大数量数据去重优先用集合,效率远高于列表双重循环。
- 查找共同元素、独有元素时,直接使用集合交集、差集运算,代码简洁高效。
- 需保持原顺序去重时,结合
dict.fromkeys()
实现(Python 3.7+)。
掌握集合的使用,能让你在数据去重、关系分析等场景中写出更简洁、高效的代码,是Python数据处理的重要工具之一。