Python集合与元组:去重利器与不可变列表,什么时候用它们?
·
Python集合与元组:去重利器与不可变列表,什么时候用它们?
上一篇文章讲了字典,这篇文章讲两个"配套"的数据结构——集合(set)和元组(tuple)。集合用于去重和集合运算,元组用于保护数据不被修改。它们各有各的用途,用对了能让代码更安全、更高效。
一句话概括
这篇文章解决一个问题:搞清楚集合(去重和集合运算)和元组(不可变数据)的用法和适用场景。
集合(set)
什么是集合
集合是无序、不重复的元素集。用 {} 表示(但不像字典那样有键值对):
# 创建集合
fruits = {"苹果", "香蕉", "橙子", "苹果", "香蕉"}
print(fruits) # {'苹果', '香蕉', '橙子'}(自动去重了!)
创建集合
# 直接创建
s = {1, 2, 3, 4, 5}
# 用 set() 从列表/字符串转换
s = set([1, 2, 2, 3, 3]) # {1, 2, 3}
s = set("hello") # {'h', 'e', 'l', 'o'}(去重)
# 空集合不能用 {},要用 set()
empty = set() # set(),不是 {}
not_empty = {1} # {1}
集合的基本操作
添加元素:
s = {1, 2, 3}
s.add(4) # {1, 2, 3, 4}
s.add(2) # {1, 2, 3, 4}(重复添加无效)
s.update([5, 6, 7]) # {1, 2, 3, 4, 5, 6, 7}(添加多个)
删除元素:
s = {1, 2, 3, 4}
s.remove(3) # {1, 2, 4}(元素不存在会报错)
s.discard(10) # {1, 2, 3, 4}(元素不存在也不报错)
s.pop() # 删除并返回任意一个元素
s.clear() # {}
集合运算(重点)
集合最强大的地方是支持数学集合运算:
a = {1, 2, 3, 4, 5}
b = {4, 5, 6, 7, 8}
# 并集:两个集合的所有元素
print(a | b) # {1, 2, 3, 4, 5, 6, 7, 8}
print(a.union(b)) # 同上
# 交集:两个集合都有的元素
print(a & b) # {4, 5}
print(a.intersection(b)) # 同上
# 差集:在a里但不在b里的元素
print(a - b) # {1, 2, 3}
print(a.difference(b)) # 同上
# 对称差集:在a或b里,但不同时在两者里
print(a ^ b) # {1, 2, 3, 6, 7, 8}
print(a.symmetric_difference(b)) # 同上
集合关系判断
s1 = {1, 2, 3}
s2 = {1, 2, 3, 4, 5}
# 子集:s1的所有元素都在s2里
print(s1.issubset(s2)) # True
print(s1 <= s2) # True
# 超集:s2包含s1的所有元素
print(s2.issuperset(s1)) # True
print(s2 >= s1) # True
# 真子集/真超集(不能相等)
print(s1 < s2) # True(s1是s2的真子集)
print(s1 < s1) # False(相等就不是真子集了)
元组(tuple)
什么是元组
元组是不可变的列表。创建后不能修改、添加、删除元素。
# 创建元组
t = (1, 2, 3, 4, 5)
t2 = 1, 2, 3, 4, 5 # 括号可以省略
# 单个元素的元组(必须有逗号)
t3 = (1,) # (1,),不是 1
t4 = (1) # 1,这是整数,不是元组
# 用 tuple() 从列表转换
t = tuple([1, 2, 3]) # (1, 2, 3)
为什么需要元组?
元组不可变,有以下几个用途:
1. 作为字典的键(因为不可变):
# 可以用元组作为键,但不能用列表
locations = {
("北京", "朝阳区"): "CBD",
("上海", "浦东区"): "陆家嘴",
}
2. 保护数据不被意外修改:
# 如果你知道某些数据不需要修改,用元组更安全
# 如果有人试图修改,会立即报错
COORDS = (40.7128, -74.0060) # 纽约坐标,不会变
3. 函数返回值多个值时用元组:
def get_stats(numbers):
return min(numbers), max(numbers), sum(numbers) / len(numbers)
result = get_stats([1, 2, 3, 4, 5])
print(result) # (1, 5, 3.0)
min_val, max_val, avg_val = result # 元组拆包
元组的基本操作
t = (1, 2, 3, 4, 5)
# 索引和切片(和列表一样)
print(t[0]) # 1
print(t[1:3]) # (2, 3)
print(t[::-1]) # (5, 4, 3, 2, 1)
# 遍历
for item in t:
print(item)
# 元组拆包
x, y, z = (1, 2, 3) # x=1, y=2, z=3
# 交换两个变量的值(利用元组拆包)
a, b = 10, 20
a, b = b, a # a=20, b=10,不需要临时变量
实战练习:去重与统计
练习1:列表去重
# 原始列表(有重复)
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5]
# 方法1:用set去重(但顺序可能改变)
unique = list(set(numbers))
print(unique) # [1, 2, 3, 4, 5](顺序变了)
# 方法2:保持顺序的去重
def unique_with_order(lst):
seen = set()
result = []
for item in lst:
if item not in seen:
seen.add(item)
result.append(item)
return result
print(unique_with_order(numbers)) # [1, 2, 3, 4, 5](顺序保持)
练习2:找出两个列表的共同元素
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
# 用集合的交集
common = set(list1) & set(list2)
print(common) # {4, 5}
练习3:找出所有不重复的单词
text1 = "python is great and python is easy to learn"
text2 = "java is also great and python is widely used"
words1 = set(text1.split())
words2 = set(text2.split())
print("两篇都有的词:", words1 & words2)
print("第一篇独有的词:", words1 - words2)
print("第二篇独有的词:", words2 - words1)
print("两篇的所有词:", words1 | words2)
集合 vs 列表 vs 元组:对比
| 特性 | 列表 list | 集合 set | 元组 tuple |
|---|---|---|---|
| 有序 | ✅ | ❌ | ✅ |
| 可重复 | ✅ | ❌ | ✅ |
| 可修改 | ✅ | ✅ | ❌(不可变) |
| 查找速度 | O(n) | O(1) | O(n) |
| 索引访问 | ✅ | ❌ | ✅ |
| 用途 | 有序数据 | 去重、集合运算 | 不可变数据 |
常见问题FAQ
Q1:什么时候用列表,什么时候用集合?
- 需要按顺序访问元素 → 列表
- 需要快速查找、去重 → 集合
- 数据不需要修改 → 元组
Q2:为什么元组不可变还重要?
元组不可变的好处:
- 线程安全:多线程环境下不会被意外修改
- 可作为字典键:列表不能做字典键,元组可以
- hashable:元组可以 hash,集合的元素可以是元组
- 性能稍好:不可变对象在某些场景下更快
Q3:怎么把元组转成列表?
t = (1, 2, 3)
lst = list(t) # [1, 2, 3]
t2 = tuple(lst) # (1, 2, 3)
注意:这是创建了新的对象,原来的元组还在。
Q4:namedtuple 是什么?
Python 标准库有一个 namedtuple,可以给元组的每个位置起名字:
from collections import namedtuple
# 定义一个命名的元组类型
Point = namedtuple('Point', ['x', 'y', 'z'])
# 创建对象
p = Point(1, 2, 3)
# 可以用名字访问,也可以用索引
print(p.x, p.y, p.z) # 1 2 3
print(p[0], p[1], p[2]) # 1 2 3
写在最后
这篇文章讲了:
- 集合(set):去重、集合运算(交/并/差/对称差)
- 元组(tuple):不可变数据、作为字典键、多值返回
三个数据结构各有各的用途:
- 列表:有序、可变、需要按索引访问
- 集合:无序、唯一性、去重和集合运算
- 元组:不可变、保护数据、hashable
下一篇文章:Python 函数,def参数详解、返回值、局部变量。
参考资料:
更多推荐


所有评论(0)