集合(Set)
学习Python集合的创建、操作和特性,掌握这个用于存储唯一元素的无序容器。
基本概念
集合(Set)是Python中的一种数据结构,用于存储不重复的元素。集合中的元素是无序的,且每个元素必须是不可变类型。
集合的特点:
- 无序:集合中的元素没有特定的顺序
- 唯一:集合中的元素不能重复
- 可变:可以添加和删除元素
- 元素必须是不可变类型:可以是数字、字符串、元组等,不能是列表、字典、集合等可变类型
- 没有索引:不能通过索引访问元素
集合的表示:用花括号 {} 包围元素,多个元素之间用逗号 , 分隔。注意:创建空集合不能使用 {},因为这会创建一个空字典,应该使用 set() 函数。
empty_set = set()
# 注意:不能使用 {} 创建空集合,这会创建一个空字典
empty_dict = {}
# 创建包含元素的集合
fruits = {'apple', 'banana', 'orange', 'apple'}
print(fruits) # 输出: {'banana', 'apple', 'orange'}(注意:重复的'apple'被自动移除了)
# 使用set()函数从其他可迭代对象创建集合
numbers_list = [1, 2, 3, 2, 4, 5, 3]
numbers_set = set(numbers_list)
print(numbers_set) # 输出: {1, 2, 3, 4, 5}(重复的元素被自动移除)
# 从字符串创建集合
word = 'hello'
char_set = set(word)
print(char_set) # 输出类似: {'h', 'e', 'l', 'o'}(重复的'l'被自动移除)
# 从元组创建集合
colors_tuple = ('red', 'green', 'blue', 'red')
colors_set = set(colors_tuple)
print(colors_set) # 输出: {'red', 'green', 'blue'}(重复的'red'被自动移除)
集合的基本操作
我们可以对集合进行添加、删除元素等基本操作。
fruits = {'apple', 'banana', 'orange'}
# 添加单个元素
fruits.add('grape')
print(fruits) # 输出类似: {'banana', 'apple', 'orange', 'grape'}
# 尝试添加重复元素(不会有效果)
fruits.add('apple')
print(fruits) # 输出和上面相同,因为'apple'已经在集合中
# 添加多个元素
fruits.update(['watermelon', 'pear', 'pineapple'])
print(fruits) # 输出类似: {'banana', 'apple', 'orange', 'grape', 'watermelon', 'pear', 'pineapple'}
# 删除指定元素(如果元素不存在会引发KeyError)
fruits.remove('orange')
print(fruits) # 输出类似: {'banana', 'apple', 'grape', 'watermelon', 'pear', 'pineapple'}
# 删除指定元素(如果元素不存在不会引发错误)
fruits.discard('orange') # 不会引发错误,因为'orange'已经不在集合中
print(fruits) # 输出和上面相同
# 随机删除并返回一个元素
random_fruit = fruits.pop()
print("随机删除的元素: ", random_fruit)
print(fruits) # 输出中不再包含被删除的元素
# 清空集合
fruits.clear()
print(fruits) # 输出: set()
# 删除整个集合
del fruits
# print(fruits) # 引发NameError,因为fruits已经不存在
我们还可以使用 in 关键字来检查某个元素是否在集合中:
numbers = {1, 2, 3, 4, 5}
# 检查元素是否在集合中
if 3 in numbers:
print("3在集合中")
else:
print("3不在集合中")
if 6 not in numbers:
print("6不在集合中")
集合运算
集合支持多种数学集合运算,如并集、交集、差集和对称差集等。
并集(Union)
两个集合中所有的元素(去除重复)
符号:| 或方法:union()
交集(Intersection)
两个集合中共同的元素
符号:& 或方法:intersection()
差集(Difference)
在第一个集合中但不在第二个集合中的元素
符号:- 或方法:difference()
对称差集(Symmetric Difference)
在两个集合中但不在它们交集中的元素
符号:^ 或方法:symmetric_difference()
set_a = {1, 2, 3, 4, 5}
set_b = {3, 4, 5, 6, 7}
# 并集
union_set = set_a | set_b
print("并集: ", union_set) # 输出: {1, 2, 3, 4, 5, 6, 7}
# 或者使用union()方法
union_set = set_a.union(set_b)
print("并集: ", union_set) # 输出: {1, 2, 3, 4, 5, 6, 7}
# 交集
intersection_set = set_a & set_b
print("交集: ", intersection_set) # 输出: {3, 4, 5}
# 或者使用intersection()方法
intersection_set = set_a.intersection(set_b)
print("交集: ", intersection_set) # 输出: {3, 4, 5}
# 差集
difference_set = set_a - set_b
print("差集 (set_a - set_b): ", difference_set) # 输出: {1, 2}
# 或者使用difference()方法
difference_set = set_a.difference(set_b)
print("差集 (set_a - set_b): ", difference_set) # 输出: {1, 2}
# 反过来的差集
difference_set = set_b - set_a
print("差集 (set_b - set_a): ", difference_set) # 输出: {6, 7}
# 对称差集
sym_diff_set = set_a ^ set_b
print("对称差集: ", sym_diff_set) # 输出: {1, 2, 6, 7}
# 或者使用symmetric_difference()方法
sym_diff_set = set_a.symmetric_difference(set_b)
print("对称差集: ", sym_diff_set) # 输出: {1, 2, 6, 7}
集合的包含关系
我们可以检查一个集合是否是另一个集合的子集、超集或不相交集。
子集(Subset)
如果集合A的所有元素都在集合B中,则A是B的子集
符号:<= 或方法:issubset()
真子集(Proper Subset)
如果集合A是B的子集且A不等于B,则A是B的真子集
符号:<
超集(Superset)
如果集合B的所有元素都在集合A中,则A是B的超集
符号:>= 或方法:issuperset()
真超集(Proper Superset)
如果集合A是B的超集且A不等于B,则A是B的真超集
符号:>
不相交集(Disjoint)
如果两个集合没有共同的元素,则它们是不相交的
方法:isdisjoint()
a = {1, 2, 3}
b = {1, 2, 3, 4, 5}
c = {6, 7, 8}
# 检查子集关系
print("a是b的子集吗? ", a <= b) # 输出: True
print("a是b的真子集吗? ", a < b) # 输出: True
print("b是a的子集吗? ", b <= a) # 输出: False
# 或者使用issubset()方法
print("a是b的子集吗? ", a.issubset(b)) # 输出: True
# 检查超集关系
print("b是a的超集吗? ", b >= a) # 输出: True
print("b是a的真超集吗? ", b > a) # 输出: True
print("a是b的超集吗? ", a >= b) # 输出: False
# 或者使用issuperset()方法
print("b是a的超集吗? ", b.issuperset(a)) # 输出: True
# 检查不相交集
print("a和c不相交吗? ", a.isdisjoint(c)) # 输出: True
print("a和b不相交吗? ", a.isdisjoint(b)) # 输出: False
故事化案例:学生选课系统
在学校的选课系统中,我们需要管理学生选择的课程。由于每个学生不能选择同一门课程多次,集合是解决这个问题的理想选择。
场景:学生选课系统
- 为每个学生创建一个课程集合
- 添加和删除选课
- 检查学生是否选了某门课程
- 找出两个学生共同选择的课程
- 找出一个学生选了但另一个学生没选的课程
- 统计每个学生选课的数量
代码实现:
student1_courses = {'数学', '语文', '英语', '物理', '化学'}
student2_courses = {'数学', '英语', '生物', '历史', '地理'}
student3_courses = {'语文', '物理', '化学', '政治', '音乐'}
# 检查学生是否选了某门课程
def check_course(student_name, courses, course_name:
if course_name in courses:
print(f"{student_name}选了{course_name}")
else:
print(f"{student_name}没有选{course_name}")
check_course("学生1", student1_courses, "数学")
check_course("学生1", student1_courses, "历史")
check_course("学生2", student2_courses, "生物")
# 学生添加新选课
student1_courses.add("计算机")
print("\n学生1添加计算机课后的选课: ", student1_courses)
# 学生退课
student2_courses.discard("地理")
print("\n学生2退掉地理课后的选课: ", student2_courses)
# 找出两个学生共同选择的课程(交集)
common_courses = student1_courses & student2_courses
print("\n学生1和学生2共同选择的课程: ", common_courses)
# 找出学生1选了但学生2没选的课程(差集)
student1_only = student1_courses - student2_courses
print("\n学生1选了但学生2没选的课程: ", student1_only)
# 找出两个学生一共选了哪些课程(并集)
all_courses = student1_courses.union(student2_courses)
print("\n学生1和学生2一共选了这些课程: ", all_courses)
# 统计每个学生选课的数量
print("\n学生1选课数量: ", len(student1_courses))
print("学生2选课数量: ", len(student2_courses))
print("学生3选课数量: ", len(student3_courses))
# 找出三个学生都选了的课程
common_all = student1_courses.intersection(student2_courses, student3_courses)
print("\n三个学生都选了的课程: ", common_all) # 输出可能为空集合
# 找出至少有一个学生选了的课程
all_courses_all = student1_courses.union(student2_courses, student3_courses)
print("\n至少有一个学生选了的课程总数: ", len(all_courses_all))
print(all_courses_all)
运行上面的代码,输出结果为:
学生1选了数学
学生1没有选历史
学生2选了生物
学生1添加计算机课后的选课: {'数学', '语文', '英语', '物理', '化学', '计算机'}
学生2退掉地理课后的选课: {'数学', '英语', '生物', '历史'}
学生1和学生2共同选择的课程: {'数学', '英语'}
学生1选了但学生2没选的课程: {'语文', '物理', '化学', '计算机'}
学生1和学生2一共选了这些课程: {'数学', '语文', '英语', '物理', '化学', '生物', '历史', '计算机'}
学生1选课数量: 6
学生2选课数量: 4
学生3选课数量: 5
三个学生都选了的课程: set()
至少有一个学生选了的课程总数: 11
{'数学', '语文', '英语', '物理', '化学', '生物', '历史', '政治', '音乐', '计算机'}
练习题
1 集合基本操作
1. 创建一个包含你喜欢的5种颜色的集合 2. 添加一种新的颜色 3. 尝试添加一种已经存在的颜色(观察会发生什么) 4. 删除一种颜色 5. 尝试删除一种不存在的颜色(使用discard方法) 6. 检查集合中是否包含特定的颜色 7. 统计集合中元素的数量
favorite_colors = {'red', 'blue', 'green', 'yellow', 'purple'}
print("原始集合: ", favorite_colors)
# 添加一种新的颜色
favorite_colors.add('orange')
print("添加橙色后: ", favorite_colors)
# 尝试添加一种已经存在的颜色
favorite_colors.add('red') # 不会有效果,因为'red'已经在集合中
print("尝试添加已存在的红色后: ", favorite_colors) # 集合保持不变
# 删除一种颜色
favorite_colors.remove('yellow')
print("删除黄色后: ", favorite_colors)
# 尝试删除一种不存在的颜色(使用discard方法)
favorite_colors.discard('pink') # 不会引发错误,即使'pink'不在集合中
print("尝试删除不存在的粉色后: ", favorite_colors) # 集合保持不变
# 检查集合中是否包含特定的颜色
if 'blue' in favorite_colors:
print("集合中包含蓝色")
else:
print("集合中不包含蓝色")
if 'black' not in favorite_colors:
print("集合中不包含黑色")
# 统计集合中元素的数量
print("集合中颜色的数量: ", len(favorite_colors))
2 找出共同朋友
1. 创建两个集合,表示你和你的朋友各自的朋友圈 2. 找出你们共同的朋友(交集) 3. 找出只在你朋友圈中的朋友(差集) 4. 找出只在你朋友朋友圈中的朋友(差集) 5. 找出你们所有的朋友(并集) 6. 找出只在一方朋友圈中的朋友(对称差集)
my_friends = {'张三', '李四', '王五', '赵六', '孙七'}
friend_friends = {'李四', '赵六', '周八', '吴九', '郑十'}
print("我的朋友: ", my_friends)
print("朋友的朋友: ", friend_friends)
# 找出共同的朋友(交集)
common_friends = my_friends & friend_friends
print("\n我们共同的朋友: ", common_friends)
# 找出只在我朋友圈中的朋友(差集)
my_only_friends = my_friends - friend_friends
print("只有我认识的朋友: ", my_only_friends)
# 找出只在朋友朋友圈中的朋友(差集)
friend_only_friends = friend_friends - my_friends
print("只有朋友认识的朋友: ", friend_only_friends)
# 找出我们所有的朋友(并集)
all_friends = my_friends.union(friend_friends)
print("\n我们认识的所有朋友: ", all_friends)
print("朋友总数: ", len(all_friends))
# 找出只在一方朋友圈中的朋友(对称差集)
exclusive_friends = my_friends ^ friend_friends
print("\n只在一方朋友圈中的朋友: ", exclusive_friends)
print("数量: ", len(exclusive_friends))
# 验证:对称差集等于两个差集的并集
print("\n验证: 对称差集是否等于两个差集的并集: ",
exclusive_friends == my_only_friends.union(friend_only_friends))
3 去除列表中的重复元素
1. 创建一个包含重复元素的列表 2. 使用集合去除列表中的重复元素 3. 将去重后的集合转回列表 4. 保持原列表中元素的顺序 5. 编写一个函数,接受一个列表作为参数,返回一个去除重复元素并保持原有顺序的新列表
original_list = [1, 2, 3, 2, 4, 5, 3, 6, 7, 5, 8, 9, 1]
print("原始列表: ", original_list)
print("原始列表长度: ", len(original_list))
# 2. 使用集合去除列表中的重复元素
unique_set = set(original_list)
print("\n去重后的集合: ", unique_set)
print("集合长度: ", len(unique_set))
# 3. 将去重后的集合转回列表
unique_list = list(unique_set)
print("\n转回列表: ", unique_list) # 注意:顺序可能与原列表不同
print("列表长度: ", len(unique_list))
# 4. 保持原列表中元素的顺序
# 方法1:使用字典(Python 3.7+ 保持插入顺序)
ordered_unique_list = list(dict.fromkeys(original_list))
print("\n保持顺序的去重列表 (方法1): ", ordered_unique_list)
# 方法2:使用循环
ordered_unique_list2 = []
for item in original_list:
if item not in ordered_unique_list2:
ordered_unique_list2.append(item)
print("保持顺序的去重列表 (方法2): ", ordered_unique_list2)
# 5. 编写一个函数,接受一个列表作为参数,返回一个去除重复元素并保持原有顺序的新列表
def remove_duplicates_preserve_order(input_list:
"""
去除列表中的重复元素并保持原有顺序
参数:
input_list: 输入列表
返回:
去除重复元素并保持原有顺序的新列表
"""
return list(dict.fromkeys(input_list))
# 测试函数
result_list = remove_duplicates_preserve_order(original_list)
print("\n使用函数处理后的列表: ", result_list)
print("处理后的列表长度: ", len(result_list))
# 测试其他类型的列表
string_list = ['apple', 'banana', 'apple', 'orange', 'banana', 'grape']
result_string_list = remove_duplicates_preserve_order(string_list)
print("\n字符串列表处理结果: ", result_string_list)
4 集合关系判断
1. 创建三个集合:A(包含1, 2, 3, 4, 5)、B(包含3, 4, 5)、C(包含6, 7, 8) 2. 判断B是否是A的子集 3. 判断A是否是B的超集 4. 判断A和C是否没有交集(即是否不相交) 5. 验证A和B的交集是否等于B
A = {1, 2, 3, 4, 5}
B = {3, 4, 5}
C = {6, 7, 8}
print("集合 A: ", A)
print("集合 B: ", B)
print("集合 C: ", C)
# 2. 判断B是否是A的子集
is_subset = B.issubset(A)
print("\nB是A的子集吗? ", is_subset)
# 也可以使用运算符 <=
print("使用运算符检查: ", B <= A)
# 3. 判断A是否是B的超集
is_superset = A.issuperset(B)
print("\nA是B的超集吗? ", is_superset)
# 也可以使用运算符 >=
print("使用运算符检查: ", A >= B)
# 4. 判断A和C是否没有交集(即是否不相交)
is_disjoint = A.isdisjoint(C)
print("\nA和C没有交集吗? ", is_disjoint)
# 也可以通过检查交集是否为空来判断
print("通过交集检查: ", len(A & C) == 0)
# 5. 验证A和B的交集是否等于B
intersection_AB = A & B
is_intersection_equal_B = intersection_AB == B
print("\nA和B的交集等于B吗? ", is_intersection_equal_B)
print("A和B的交集: ", intersection_AB)
5 模拟用户兴趣标签管理
1. 创建一个表示用户兴趣标签的集合 2. 添加新的兴趣标签 3. 移除不再感兴趣的标签 4. 检查用户是否对某个标签感兴趣 5. 与另一个用户的兴趣标签进行比较,找出共同兴趣 6. 找出只在一方感兴趣的标签 7. 计算用户兴趣标签的总数
user_tags = {'编程', '数学', '音乐', '电影', '游戏'}
print("用户初始兴趣标签: ", user_tags)
# 2. 添加新的兴趣标签
user_tags.add('摄影')
user_tags.add('旅行')
print("\n添加新标签后: ", user_tags)
# 3. 移除不再感兴趣的标签
user_tags.remove('游戏')
print("\n移除标签后: ", user_tags)
# 4. 检查用户是否对某个标签感兴趣
tag_to_check = '音乐'
if tag_to_check in user_tags:
print(f"\n用户对{tag_to_check}感兴趣")
else:
print(f"\n用户对{tag_to_check}不感兴趣")
# 5. 与另一个用户的兴趣标签进行比较,找出共同兴趣
friend_tags = {'摄影', '旅行', '美食', '电影', '运动'}
common_interests = user_tags & friend_tags
print("\n朋友的兴趣标签: ", friend_tags)
print("共同兴趣: ", common_interests)
print("共同兴趣数量: ", len(common_interests))
# 6. 找出只在一方感兴趣的标签
exclusive_interests = user_tags ^ friend_tags
print("\n只在一方感兴趣的标签: ", exclusive_interests)
# 7. 计算用户兴趣标签的总数
print("\n用户兴趣标签总数: ", len(user_tags))
print("朋友兴趣标签总数: ", len(friend_tags))
print("所有不同的兴趣标签总数: ", len(user_tags | friend_tags))