查看全课大纲(第 24 / 51 节)
- 1.Python 是什么?为什么值得学?
- 2.如何为 Python 编程准备一个“全家桶”环境?
- 3.Python 有哪几种执行方法?
- 4.行与缩进到底有什么用?
- 5.注释有什么用,怎么写?
- 6.变量:如何给数据起个好名字?
- 7.运算符的优先级和常见坑点是什么?
- 8.Python 中,数字和布尔值究竟有哪几种?
- 9.输入函数 `input()` 和文件读取 `open()` 怎么用?
- 10.如何将程序的结果展示给用户或保存下来?
- 11.CSV 文件怎么读怎么写才方便?
- 12.列表是什么,如何创建和访问它?
- 13.列表的修改操作,有哪些方法?
- 14.列表切片为什么能取到部分元素?排序和查找又该怎么用?
- 15.判断语句:如何让程序根据条件做不同的事?
- 16.for 循环如何遍历序列中的元素?
- 17.while 循环什么时候才会停?
- 18.while 循环的结束条件,你写对了吗?
- 19.循环中途想提前结束,怎么办?
- 20.`break` 和 `continue` 到底有什么区别?
- 21.列表推导式如何让代码更简洁高效?
- 22.字符串怎么定义、拼接和操作?
- 23.元组:为什么定义单个元素时要加逗号?
- 24.集合(set)怎么用?如何快速去重和做集合运算?
- 25.字典是什么,为什么比列表更方便?
- 26.字典的增删改查与遍历,如何避免 KeyError?
- 27.函数里的变量,为什么有的能用有的不能用?
- 28.在函数内部修改全局变量,为什么有时不生效?
- 29.函数里能修改全局变量吗?返回值怎么用?
- 30.匿名函数:如何用 lambda 快速定义简单函数?
- 31.面向对象编程是什么,为什么需要它?
- 32.类中的方法和属性到底怎么定义和使用?
- 33.如何控制对对象内部属性和方法的访问?
- 34.异常发生时,程序会怎样继续执行?
- 35.如何组织代码:包和模块
- 36.`if __name__ == '__main__'` 到底有什么用?
- 37.如何用 IDE 的 Debug 功能排查程序错误?
- 38.Matplotlib 绘图的第一步该做什么?
- 39.Figure 是什么,如何设置图形尺寸?
- 40.如何自定义 Matplotlib 的坐标轴?
- 41.如何为图表添加图例,让不同曲线一目了然?
- 42.饼图怎么画才能直观展示数据占比?
- 43.如何用 Matplotlib 绘制散点图?
- 44.柱状图怎么画?
- 45.如何使用 Matplotlib 绘制等高线图?
- 46.如何在 Matplotlib 中绘制子图?
- 47.zip 函数如何把多个列表“打包”在一起?
- 48.如何给可迭代对象加上索引?
- 49.random 模块如何生成随机数?
- 50.math 模块怎么用?
- 51.Counter 如何快速统计元素出现次数?
集合(set)怎么用?如何快速去重和做集合运算?
约 22 分钟
小象实战讲义 · Python 编程从入门到实践
你已经学习了列表和元组这两种有序序列。这一节,我们将学习 Python 中的另一种重要数据结构——集合(set)。集合的核心特点是无序和元素不重复,这使得它在数据去重、成员关系判断以及集合运算(如交集、并集)等场景下非常合适。学完本节,你将掌握如何创建、操作集合,并利用其特性解决实际问题。
💡 核心导读
- 集合是什么:无序、元素不重复的容器,可存储不同类型的数据。
- 如何创建集合:使用花括号
{}或set()函数,特别注意空集合的创建方法。 - 核心操作:添加元素(
add、update)、删除元素(remove、discard、pop、clear)、判断成员关系(in、not in)。 - 集合运算:交集(
&)、并集(|)、差集(-)、对称差集(^),以及前三种运算的方法写法。 - 典型应用:利用集合对列表、元组等序列进行快速去重。
集合的定义与特点
集合(set)是 Python 中一种无序存储不重复元素的容器。同一个集合内可以存储不同数据类型的元素。
它与列表、元组的主要区别有两点:
- 无序:集合中的元素没有固定的顺序,因此不能通过下标(索引)来访问特定位置的元素。
- 元素唯一:集合会自动确保其中的每个元素都是唯一的,重复的元素会被自动过滤掉。
因为无序,直接打印集合时元素的排列顺序并不固定。本节示例统一用 sorted() 排好序再打印,方便对照;集合里同时有字符串和整数时,用 key=str 按字符串形式排序。
# 定义一个集合,包含字符串和一个整数
student_set = {"xiaoming", "xiaoqiang", "xiaobai", "lisi", 13}
print(type(student_set))
print(len(student_set)) # 使用 len() 获取元素个数
print(sorted(student_set, key=str)) # 排序后打印,便于查看内容<class 'set'>
5
[13, 'lisi', 'xiaobai', 'xiaoming', 'xiaoqiang']创建集合的几种方式
1. 使用花括号 {}
这是最直接的方式,用逗号分隔元素,例如 fruits = {"apple", "banana", "orange"}。
2. 使用 set() 函数从其他序列转换
set() 函数可以将列表、元组、字符串等转换为集合,并自动去重。这是最常用的去重方法。需要注意:如果传入的是字符串,会把字符串按字符拆开,每个字符作为独立元素。
3. 创建空集合
特别注意:不能使用 {} 来创建空集合,因为 {} 在 Python 中表示一个空字典。创建空集合必须使用 set() 函数。
# 从列表创建集合(去重)
id_list = ["id1", "id2", "id3", "id1", "id2"]
distinct_set_from_list = set(id_list)
print("从列表创建的集合:", sorted(distinct_set_from_list))
# 从元组创建集合(去重)
id_tuple = ("id1", "id2", "id3", "id1", "id2")
distinct_set_from_tuple = set(id_tuple)
print("从元组创建的集合:", sorted(distinct_set_from_tuple))
# 从字符串创建集合:每个字符成为独立元素,并去重
string_set = set("hello") # 'l' 出现两次,集合中只保留一个
print("从字符串创建的集合:", sorted(string_set))
# 空字典与空集合
empty_dict = {}
empty_set = set()
print(type(empty_dict))
print(type(empty_set))
print(empty_set)从列表创建的集合: ['id1', 'id2', 'id3']
从元组创建的集合: ['id1', 'id2', 'id3']
从字符串创建的集合: ['e', 'h', 'l', 'o']
<class 'dict'>
<class 'set'>
set()集合的基本操作
判断元素是否存在
虽然不能按索引访问,但可以用 in 和 not in 关键字快速判断一个元素是否在集合中,判断结果是 True 或 False。
添加元素
add(element):向集合中添加单个元素。如果元素已存在,则无任何效果。update(序列):将一个序列(如列表、元组、另一个集合、字符串)中的所有元素添加到集合中,同时去重。对于字符串,会将其拆分为单个字符添加。
删除元素
集合提供了几种删除元素的方法,它们的关键区别在于处理“元素不存在”时的行为。
| 方法 | 作用 | 元素不存在时的行为 |
|---|---|---|
remove(element) | 删除指定元素。 | 抛出 KeyError 异常。 |
discard(element) | 删除指定元素。 | 静默忽略,不报错。 |
pop() | 随机删除并返回一个元素。 | — |
clear() | 清空集合,使其变为空集合。 | 总是成功。 |
如何选择?
- 当你确定元素一定在集合中,或者希望元素不存在时能明确感知到错误,使用
remove。 - 当你只是想尝试删除,元素不存在也没关系,使用
discard。 - 当你只关心集合中还剩多少元素、不关心删掉的是哪一个,可以使用
pop。
下面把判断、添加、删除放在同一个可运行示例里,方便对照输出:
distinct_set = set(["id1", "id2", "id3"])
print("当前集合:", sorted(distinct_set))
# 使用 in / not in 判断元素是否存在
user_id = "id1"
if user_id in distinct_set:
print("{} 存在".format(user_id))
user_id = "id5"
if user_id not in distinct_set:
print("{} 不存在".format(user_id))
# 添加元素
name_set = {"zhangsan", "lisi"}
name_set.add("wangwu")
print("add 之后:", sorted(name_set))
name_set.update(["悟空", "八戒"])
print("update 列表之后:", sorted(name_set))
name_set.update(("白龙马", "小燕子", "八戒")) # '八戒'已存在,不会重复添加
print("update 元组之后:", sorted(name_set))
name_set.update({"张飞", "李逵"}) # 合并另一个集合
print("update 集合之后:", sorted(name_set))
name_set.update("沙和尚") # 字符串会被拆成单个字符
print("update 字符串之后:", sorted(name_set))
# 删除元素
name_set2 = {"悟空", "八戒", "沙僧"}
name_set2.remove("悟空") # 元素存在,成功删除
print("remove('悟空')后:", sorted(name_set2))
# name_set2.remove("西游记") # 如果取消注释,会抛出 KeyError
ret1 = name_set2.discard("沙僧")
print("discard('沙僧')后:", sorted(name_set2))
print("discard 返回值:", ret1) # discard 无论成功与否都返回 None
ret2 = name_set2.discard("悟空") # 元素已不存在,静默忽略
print("discard('悟空')后(元素已不存在):", sorted(name_set2))
print("discard 返回值:", ret2)
item = name_set2.pop() # 删除并返回一个元素
print("pop() 删除了:", item)
print("pop() 后:", sorted(name_set2))
name_set2.clear()
print("clear() 后:", name_set2)当前集合: ['id1', 'id2', 'id3']
id1 存在
id5 不存在
add 之后: ['lisi', 'wangwu', 'zhangsan']
update 列表之后: ['lisi', 'wangwu', 'zhangsan', '八戒', '悟空']
update 元组之后: ['lisi', 'wangwu', 'zhangsan', '八戒', '小燕子', '悟空', '白龙马']
update 集合之后: ['lisi', 'wangwu', 'zhangsan', '八戒', '小燕子', '张飞', '悟空', '李逵', '白龙马']
update 字符串之后: ['lisi', 'wangwu', 'zhangsan', '八戒', '和', '小燕子', '尚', '张飞', '悟空', '李逵', '沙', '白龙马']
remove('悟空')后: ['八戒', '沙僧']
discard('沙僧')后: ['八戒']
discard 返回值: None
discard('悟空')后(元素已不存在): ['八戒']
discard 返回值: None
pop() 删除了: 八戒
pop() 后: []
clear() 后: set()集合的运算
集合支持常见的集合运算,非常直观:交集取两个集合共有的元素;并集取两个集合的全部元素(去重);差集取只在被减集合中存在的元素;对称差集取只在其一集合中出现的元素。交集、并集、差集都同时给出运算符和对应方法两种写法。
set_a = {1, 2, 4, 7}
set_b = {2, 5, 8, 9}
# 1. 交集:两个集合共有的元素
print("交集(&):", sorted(set_a & set_b))
print("交集(intersection):", sorted(set_a.intersection(set_b)))
# 2. 并集:两个集合所有的元素(去重)
print("并集(|):", sorted(set_a | set_b))
print("并集(union):", sorted(set_a.union(set_b)))
# 3. 差集:只在 set_a 中、不在 set_b 中的元素
print("差集(-):", sorted(set_a - set_b))
print("差集(difference):", sorted(set_a.difference(set_b)))
# 4. 对称差集:只在其中一个集合中出现的元素
print("对称差集(^):", sorted(set_a ^ set_b))交集(&): [2]
交集(intersection): [2]
并集(|): [1, 2, 4, 5, 7, 8, 9]
并集(union): [1, 2, 4, 5, 7, 8, 9]
差集(-): [1, 4, 7]
差集(difference): [1, 4, 7]
对称差集(^): [1, 4, 5, 7, 8, 9]📝 动手练一练
- 你有一个记录网站用户访问日期的列表,其中包含大量重复日期。请使用集合快速找出网站有哪些不同的访问日期。
- 有两个学习小组,A组有成员
['张三', '李四', '王五', '赵六'],B组有成员['王五', '赵六', '孙七', '周八']。请找出: a) 同时参加了两个小组的成员。 b) 所有参与了至少一个小组的成员。 c) 只参加了A组但没有参加B组的成员。
👉 点击查看参考答案
思路:
- 直接将列表转换为集合即可去重,再用
sorted()让结果有序、便于查看。 - 利用集合运算:交集求共同成员,并集求所有成员,差集求仅属于A组的成员。
# 1. 访问日期去重
visit_dates = ["2023-10-01", "2023-10-02", "2023-10-01", "2023-10-03", "2023-10-02"]
unique_dates = sorted(set(visit_dates))
print("不同的访问日期有: {}".format(unique_dates))
# 2. 学习小组分析
group_a = set(['张三', '李四', '王五', '赵六'])
group_b = set(['王五', '赵六', '孙七', '周八'])
# a) 同时参加两个小组的成员(交集)
print("同时参加两个小组的成员: {}".format(sorted(group_a & group_b)))
# b) 所有参与的成员(并集)
print("所有参与的成员: {}".format(sorted(group_a | group_b)))
# c) 只参加A组的成员(差集)
print("只参加A组的成员: {}".format(sorted(group_a - group_b)))不同的访问日期有: ['2023-10-01', '2023-10-02', '2023-10-03']
同时参加两个小组的成员: ['王五', '赵六']
所有参与的成员: ['周八', '孙七', '张三', '李四', '王五', '赵六']
只参加A组的成员: ['张三', '李四']常见错误
| 错误写法 | 现象或报错 | 原因 | 正确写法 |
|---|---|---|---|
empty_set = {} | type(empty_set) 结果是 dict | {} 在 Python 中默认表示空字典。 | empty_set = set() |
my_set.remove('不存在的元素') | KeyError: '不存在的元素' | remove() 要求元素必须存在,否则报错。 | 先使用 in 判断,或改用 discard()。 |
试图用下标访问 my_set[0] | TypeError: 'set' object is not subscriptable | 集合是无序的,不支持索引访问。 | 用 in 判断成员关系,或先用 sorted() 转成有序列表再按下标取。 |
name_set.update("沙和尚") 以为会添加一个元素 | 集合里多出“沙”“和”“尚”三个元素 | update 接收的是序列,字符串会被拆成单个字符逐个添加。 | 需要整体添加一个字符串时用 add("沙和尚")。 |
小结
- 集合(set) 是一种无序、元素不重复的容器,常用于快速去重和成员关系判断。
- 创建集合使用花括号
{}或set()函数。创建空集合必须用set()。 - 使用
in和not in判断元素是否在集合中。 - 添加元素:
add()用于添加单个元素;update()用于添加一个序列中的所有元素(字符串会被拆成字符)。 - 删除元素:根据需求选择
remove()(严格)、discard()(宽松)、pop()(返回被删元素)或clear()(清空)。 - 集合运算:交集(
&)、并集(|)、差集(-)、对称差集(^);前三种还可以用intersection()、union()、difference()方法完成。
📋 行动清单
- 尝试将一个包含重复项的列表转换为集合,观察去重效果。
- 分别使用
remove('不存在')和discard('不存在'),体会两者的区别。 - 创建两个集合,分别练习使用运算符和方法进行交集、并集、差集的计算。
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。
- 下载第3章代码包:集合(含1 个 Notebook)ZIP · 2KB