【Python】集合
目录
- 集合
- 集合基本概念
- 创建集合
- 访问集合项目
- 添加集合项目
- 删除集合项
- 循环集合
- 连接集合
- 复制集合
- 集合运算符
- 集合方法
- 冻结集合
集合
集合基本概念
什么是集合(Set)?
- 集合 是一种 无序、可迭代、元素唯一 的数据结构。
- 集合的底层是用 哈希表(hash table) 实现的。
- 和数学集合类似,可以进行 交集、并集、差集、对称差集 等运算。
基本特性
- 无序:集合中的元素没有顺序,不能通过下标访问。
- 唯一性:集合中不会出现重复元素。
- 可变性:集合本身是可变的(可以添加、删除元素),但元素必须是 不可变对象(比如 int、str、tuple 可以,list、dict 不行)。
创建集合
创建空集合
注意:{}
默认是字典,要创建空集合必须用 set()
。
s = set()
print(s) # set()
print(type(s)) # <class 'set'>
使用花括号 {}
创建集合
s = {1, 2, 3}
print(s) # {1, 2, 3}
特点:
- 元素 自动去重
s = {1, 2, 2, 3, 1}
print(s) # {1, 2, 3}
- 元素必须是 可哈希类型(int、str、tuple 可以,list、dict 不行)
s = {1, "abc", (1, 2)}
print(s) # {1, (1, 2), 'abc'}# ❌ 错误示例:
s = {[1, 2], 3}
# TypeError: unhashable type: 'list'
使用 set(iterable)
创建
几乎任何 可迭代对象 都能转成集合。
从列表创建
s = set([1, 2, 2, 3])
print(s) # {1, 2, 3}
从元组创建
s = set((1, 2, 3, 2))
print(s) # {1, 2, 3}
从字符串创建
s = set("hello")
print(s) # {'h', 'e', 'l', 'o'}
从字典创建,默认只会取 字典的 key
d = {"a": 1, "b": 2}
s = set(d)
print(s) # {'a', 'b'}
使用集合推导式(Set Comprehension)
类似列表推导式,但用花括号 {}
。
s = {x**2 for x in range(5)}
print(s) # {0, 1, 4, 9, 16}
可以加条件:
s = {x for x in range(10) if x % 2 == 0}
print(s) # {0, 2, 4, 6, 8}
从其他集合复制
s1 = {1, 2, 3}
s2 = set(s1) # 拷贝方式1
s3 = s1.copy() # 拷贝方式2print(s2, s3) # {1, 2, 3} {1, 2, 3}
创建不可变集合:frozenset
如果你不希望集合被修改,可以用 frozenset
。
fs = frozenset([1, 2, 3])
print(fs) # frozenset({1, 2, 3})# ❌ 不能修改
# fs.add(4) -> AttributeError: 'frozenset' object has no attribute 'add'
创建大集合(性能优化)
- 对大规模数据,直接用
set()
比逐个add()
更快。
nums = range(1000000)
s = set(nums) # ✅ 更快
- 推导式方式也很常用:
s = {i for i in range(1000000)} # 速度也很快
对比表
创建方式 | 示例 | 特点 |
---|---|---|
空集合 | set() | {} 会变成字典 |
直接字面量 | {1, 2, 3} | 简洁,常用 |
通过 set() | set([1, 2, 3]) | 可从任意可迭代对象 |
推导式 | {x**2 for x in range(5)} | 灵活,可加条件 |
拷贝 | set(s1) / s1.copy() | 复制已有集合 |
不可变集合 | frozenset([1, 2]) | 可作为字典 key |
访问集合项目
集合访问的基本概念
- 集合(set) 是无序、唯一元素的容器。
- 不能通过索引或键访问(不像列表用
list[0]
或字典用dict['key']
)。 - 访问集合的元素主要依靠:
- 迭代(for 循环、推导式)
- 成员运算符(in / not in)
- 集合运算(子集、交集等)
使用 for
循环访问集合元素
集合是可迭代对象,可以直接用 for
循环遍历:
langs = {"C", "C++", "Java", "Python"}for lang in langs:print(lang)
可能输出(注意集合无序,每次顺序可能不同):
Python
C
C++
Java
要点:
- 无序性:访问顺序不确定。
- 唯一性:不会有重复元素。
使用推导式访问集合元素
推导式提供了一种简洁的写法,可以在访问时直接做操作。
my_set = {1, 2, 3, 4, 5}
squares = [x**2 for x in my_set] # 转成列表
print(squares)
输出:
[1, 4, 9, 16, 25]
也可以生成 新的集合:
evens = {x for x in my_set if x % 2 == 0}
print(evens) # {2, 4}
检查集合中是否存在某元素
用 in
和 not in
运算符:
langs = {"C", "C++", "Java", "Python"}# 检查元素是否存在
if "Java" in langs:print("Java is present in the set.")# 检查元素是否不存在
if "SQL" not in langs:print("SQL is not present in the set.")
输出:
Java is present in the set.
SQL is not present in the set.
复杂度:集合查找平均时间复杂度是 O(1),比列表快很多。
从集合访问子集(Subset)
-
判断一个集合是否是另一个集合的子集
original_set = {1, 2, 3, 4} print({1, 2}.issubset(original_set)) # True print({1, 5}.issubset(original_set)) # False
-
判断超集
print(original_set.issuperset({1, 2})) # True
-
使用
itertools
生成所有子集(幂集)import itertoolsoriginal_set = {1, 2, 3, 4}# 所有包含两个元素的子集 subsets_with_two_elements = [set(subset) for subset in itertools.combinations(original_set, 2)] print(subsets_with_two_elements)
输出:
[{1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4}, {3, 4}]
转换集合以访问元素
有时需要“伪索引”访问,可以先转换为列表/元组:
s = {"apple", "banana", "cherry"}
lst = list(s)
print(lst[0]) # 可以索引访问
缺点:转换后 顺序仍不固定(集合本身无序)。
访问集合时的运算
集合访问不仅限于迭代,还常结合数学运算使用。
交集(访问共同元素)
a = {"Python", "Java", "C++"}
b = {"Python", "Rust"}
print(a & b) # {'Python'}
差集(访问独有元素)
print(a - b) # {'Java', 'C++'}
对称差集(只在一个集合中的元素)
print(a ^ b) # {'Java', 'C++', 'Rust'}
集合访问的核心方式
方式 | 示例 | 适用场景 |
---|---|---|
for 循环 | for x in s: print(x) | 遍历集合 |
推导式 | [x**2 for x in s] | 一边访问一边生成结果 |
成员运算符 | if x in s | 快速查找元素 |
子集关系 | a.issubset(b) | 判断集合关系 |
幂集生成 | itertools.combinations | 枚举子集 |
转换为列表 | list(s)[0] | 临时索引访问 |
添加集合项目
基础概念
- 集合是可变的 → 可以随时添加元素。
- 集合中的元素必须是不可变的对象(如
int
、str
、tuple
),不能是list
、dict
、另一个set
。 - 添加元素时自动去重:重复元素不会被插入。
使用 add()
添加单个元素
语法
set.add(element)
- 只能添加 一个元素。
- 如果元素已存在,集合不变。
示例
language = set()language.add("C")
language.add("C++")
language.add("Java")
language.add("Python")
language.add("Python") # 重复添加不会报错,但不会插入print("Updated Set:", language)
可能输出(无序):
Updated Set: {'Python', 'Java', 'C++', 'C'}
注意:
s = set()
s.add([1, 2]) # ❌ 报错:list是可变的,不能作为集合元素
s.add((1, 2)) # ✅ tuple是不可变的,可以添加
使用 update()
添加多个元素
语法
set.update(iterable)
- 接受任意可迭代对象(列表、元组、字符串、集合等)。
- 可一次性插入多个元素。
示例 1:添加单个可迭代对象
my_set = {1, 2, 3}
my_set.update([4])
print("Updated Set:", my_set)
输出:
Updated Set: {1, 2, 3, 4}
示例 2:添加多个集合
lang1 = {"C", "C++", "Java", "Python"}
lang2 = {"PHP", "C#", "Perl"}
lang1.update(lang2)
print(lang1)
输出:
{'Python', 'C++', 'C#', 'C', 'Java', 'PHP', 'Perl'}
示例 3:字符串被当作字符集合
set1 = set("Hello")
set1.update("World")
print(set1)
输出(无序):
{'H', 'r', 'o', 'd', 'W', 'l', 'e'}
使用集合运算 union()
/ |
语法
set1.union(set2, ...)
set1 | set2 | ...
- 返回 新集合,不修改原集合。
- 合并多个集合/可迭代对象,自动去重。
示例
lang1 = {"C", "C++", "Java", "Python"}
lang2 = {"PHP", "C#", "Perl"}
lang3 = {"SQL", "C#"}combined_set1 = lang1.union(lang2)
combined_set2 = lang2 | lang3 print("Combined Set1:", combined_set1)
print("Combined Set2:", combined_set2)
输出:
Combined Set1: {'C#', 'Perl', 'C++', 'Java', 'PHP', 'Python', 'C'}
Combined Set2: {'C#', 'Perl', 'PHP', 'SQL'}
示例:union 接收序列
lang1 = {"C", "C++", "Java", "Python"}
lang2 = ["PHP", "C#", "Perl"]
lang3 = lang1.union(lang2)
print(lang3)
输出:
{'PHP', 'C#', 'Python', 'C', 'Java', 'C++', 'Perl'}
使用 集合推导式(Set Comprehension)
- 一种 声明式写法,用来快速生成新集合。
- 适合根据已有数据 批量添加处理后的元素。
示例 1:生成平方数集合
numbers = [1, 2, 3, 4, 5]
squares_set = {num ** 2 for num in numbers}
print("Squares Set:", squares_set)
输出:
Squares Set: {1, 4, 9, 16, 25}
示例 2:过滤条件
numbers = [1, 2, 3, 4, 5, 6]
evens = {num for num in numbers if num % 2 == 0}
print("Even Set:", evens)
输出:
Even Set: {2, 4, 6}
添加集合元素的方式
方法 | 是否修改原集合 | 适用场景 |
---|---|---|
add() | ✅ | 添加单个元素 |
update() | ✅ | 批量添加多个元素(来自列表/元组/字符串/集合) |
union() | ❌(返回新集合) | 合并多个集合/序列,保持原集合不变 |
` | ` 运算符 | ❌(返回新集合) |
集合推导式 {expr for ...} | ❌(返回新集合) | 批量生成新集合,支持条件过滤 |
删除集合项
Python 集合(set
)是 无序、可变、唯一元素的集合。删除元素的方法非常丰富,不同方法适合不同场景。
remove()
方法 —— 删除指定元素(若不存在报错)
语法:
set.remove(element)
特点:
- 删除指定元素;
- 若元素不存在 →
KeyError
。
示例:
my_set = {"Rohan", "Physics", 21, 69.75}
print("Original:", my_set)my_set.remove("Physics") # 删除存在的元素
print("After remove:", my_set)my_set.remove("PHP") # 删除不存在的元素 → 报错
输出:
Original: {21, 69.75, 'Rohan', 'Physics'}
After remove: {21, 69.75, 'Rohan'}
KeyError: 'PHP'
discard()
方法 —— 删除指定元素(若不存在不报错)
语法:
set.discard(element)
特点:
- 删除指定元素;
- 元素不存在时 不会报错。
示例:
my_set = {"Rohan", "Physics", 21, 69.75}
print("Original:", my_set)my_set.discard("Physics") # 删除存在的元素
print("After discard:", my_set)my_set.discard("PHP") # 删除不存在的元素,不报错
print("After discard non-existent:", my_set)
pop()
方法 —— 删除并返回一个随机元素
语法:
removed = set.pop()
特点:
- 删除集合中 任意元素;
- 集合为空时 →
KeyError
。
示例:
my_set = {1, 2, 3, 4, 5}
removed = my_set.pop()
print("Removed:", removed)
print("Updated:", my_set)empty_set = set()
empty_set.pop() # ❌ 报错 KeyError
clear()
方法 —— 清空集合
语法:
set.clear()
特点: 删除集合中所有元素,集合变为空。
示例:
my_set = {1, 2, 3, 4, 5}
my_set.clear()
print("After clear:", my_set) # set()
difference_update()
—— 删除两个集合的交集
语法:
set1.difference_update(set2)
特点: 从 set1
中删除 set2
里也存在的元素。
示例:
s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7}
s1.difference_update(s2)
print(s1) # {1, 2, 3}
intersection_update()
—— 只保留交集
语法:
set1.intersection_update(set2)
特点: 删除不常见的元素,保留两者共有的。
示例:
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}
set1.intersection_update(set2)
print(set1) # {3, 4}
symmetric_difference_update()
—— 删除交集,保留不相同的
语法:
set1.symmetric_difference_update(set2)
特点: 更新集合,使其只保留两者不相同的部分。
示例:
s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7}
s1.symmetric_difference_update(s2)
print(s1) # {1, 2, 3, 6, 7}
intersection()
/ symmetric_difference()
—— 返回新集合
语法:
s3 = set1.intersection(set2) # 返回交集
s4 = set1.symmetric_difference(set2) # 返回对称差
特点: 不修改原集合,生成新集合。
示例:
s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7}print(s1.intersection(s2)) # {4, 5}
print(s1.symmetric_difference(s2)) # {1, 2, 3, 6, 7}
集合推导式(Set Comprehension)—— 按条件删除元素
语法:
new_set = {expr for elem in old_set if condition}
特点: 生成新集合,可实现“删除符合条件的元素”。
示例:
numbers = {1, 2, 3, 4, 5, 6}
# 删除偶数,保留奇数
filtered = {n for n in numbers if n % 2 != 0}
print(filtered) # {1, 3, 5}
对比表
方法 | 是否报错 | 是否修改原集合 | 删除规则 |
---|---|---|---|
remove(x) | ❌ KeyError | ✅ | 删除指定元素 |
discard(x) | ✅ 安全 | ✅ | 删除指定元素 |
pop() | ❌ KeyError | ✅ | 删除任意元素 |
clear() | ✅ | ✅ | 清空集合 |
difference_update() | ✅ | ✅ | 删除交集 |
intersection_update() | ✅ | ✅ | 只保留交集 |
symmetric_difference_update() | ✅ | ✅ | 删除交集,保留不相同 |
intersection() | ✅ | ❌ | 返回交集新集合 |
symmetric_difference() | ✅ | ❌ | 返回对称差新集合 |
集合推导式 | ✅ | ❌ | 按条件生成新集合 |
循环集合
集合(set
)本质上是 无序、不重复的可迭代容器。
- 无序 → 遍历时顺序不固定。
- 不重复 → 迭代时不会出现重复元素。
- 可迭代 → 能直接用
for
、while
、enumerate()
、推导式等方法进行循环。
for 循环遍历集合(最常用)
语法
for item in my_set:# 对 item 做操作
示例
my_set = {25, 12, 10, -21, 10, 100} # 重复元素会自动去重
for item in my_set:print("Item:", item)
输出(顺序可能不同):
Item: 100
Item: 25
Item: 10
Item: -21
Item: 12
要点:
- 集合遍历时,不会保证固定顺序。
- 如果想要有序,可以
for item in sorted(my_set)
。
while 循环 + 迭代器遍历集合
集合是可迭代对象,可以用 iter()
转换成迭代器,再用 next()
手动获取。
示例
my_set = {1, 2, 3, 4, 5}
set_iterator = iter(my_set)while True:try:item = next(set_iterator)print("Item:", item)except StopIteration:break
输出:
Item: 1
Item: 2
Item: 3
Item: 4
Item: 5
适合场景:需要手动控制迭代过程,或者在 while
中加复杂逻辑。
使用 集合推导式
集合理解式 = for 循环 + 条件过滤 + 自动去重。
语法
result = {表达式 for 变量 in 可迭代对象 if 条件}
示例
numbers = [1, 2, 3, 4, 5]
squares_of_evens = {x**2 for x in numbers if x % 2 == 0}
print(squares_of_evens)
输出:
{16, 4}
优点:一行生成集合,简洁高效。
注意:结果集合依旧无序。
使用 enumerate() 遍历集合
集合没有“索引”,但可以先转成 list
,再用 enumerate()
获取索引和值。
示例
my_set = {1, 2, 3, 4, 5}
for index, item in enumerate(list(my_set)):print("Index:", index, "Item:", item)
输出:
Index: 0 Item: 1
Index: 1 Item: 2
Index: 3 Item: 3
Index: 4 Item: 4
要点:因为集合无序 → list(my_set)
的顺序也是随机的。
结合 add() 方法 + 循环
虽然 add()
不是循环工具,但常和 for
搭配用来“逐个添加元素到集合”。
示例
my_set = set()
for i in range(5):my_set.add(i)
print(my_set)
输出:
{0, 1, 2, 3, 4}
按条件遍历
my_set = {10, 25, 30, 45, 50}
for item in my_set:if item % 2 == 0:print("Even:", item)
同时遍历多个集合(zip)
set1 = {1, 2, 3}
set2 = {"a", "b", "c"}
for x, y in zip(set1, set2):print(x, y)
因为集合无序,结果配对不可预测。
保证有序遍历
my_set = {4, 2, 8, 1}
for item in sorted(my_set):print(item)
输出:
1
2
4
8
连接集合
在 Python 中,集合(set
)的连接指的是:
把 两个或多个集合合并成一个新集合,同时自动去除重复元素。
特点:
- 无重复:合并时会自动去重。
- 无序:结果集合中的元素顺序不可预测。
- 元素必须不可变:数字、字符串、元组可以;列表、字典不行。
使用 |
运算符(最简洁)
s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8}
s3 = s1 | s2
print(s3)
输出:
{1, 2, 3, 4, 5, 6, 7, 8}
|
就是数学上的并集运算。
使用 union()
方法
s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8}
s3 = s1.union(s2)
print(s3)
输出:
{1, 2, 3, 4, 5, 6, 7, 8}
和 |
作用相同,但语义更清晰,支持多个集合:
s3 = s1.union(s2, {9, 10})
print(s3)
# {1,2,3,4,5,6,7,8,9,10}
使用 update()
方法(就地修改)
s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8}
s1.update(s2)
print(s1)
输出:
{1, 2, 3, 4, 5, 6, 7, 8}
update()
会直接修改原集合,不返回新集合。
使用解包运算符 *
s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8}
s3 = {*s1, *s2}
print(s3)
输出:
{1, 2, 3, 4, 5, 6, 7, 8}
优点:直观、简洁,支持多个集合:
s3 = {*s1, *s2, *{9, 10}}
使用集合推导式(Set Comprehension)
set1 = {1, 2, 3}
set2 = {3, 4, 5}
joined_set = {x for s in [set1, set2] for x in s}
print(joined_set)
输出:
{1, 2, 3, 4, 5}
灵活性更强,可以加过滤条件:
joined_set = {x for s in [set1, set2] for x in s if x % 2 == 0}
print(joined_set) # {2, 4}
使用迭代加法(for + add)
set1 = {1, 2, 3}
set2 = {3, 4, 5}joined_set = set()
for element in set1:joined_set.add(element)
for element in set2:joined_set.add(element)print(joined_set)
输出:
{1, 2, 3, 4, 5}
更“低层”的写法,适合需要一步步控制的场景。
保证有序合并
s1 = {3, 1, 2}
s2 = {5, 4}
result = sorted(s1 | s2)
print(result) # [1, 2, 3, 4, 5]
批量合并多个集合
sets = [{1, 2}, {2, 3}, {3, 4}]
merged = set().union(*sets)
print(merged) # {1, 2, 3, 4}
合并集合 + 条件过滤
s1 = {1, 2, 3}
s2 = {3, 4, 5}
merged = {x for x in (s1 | s2) if x > 2}
print(merged) # {3, 4, 5}
复制集合
在 Python 中,复制集合就是:
创建一个 新集合,包含与原集合相同的元素,但 与原集合互不影响。
和直接赋值不同:
a = {1, 2, 3}
b = a # 只是引用
b.add(4)
print(a) # {1, 2, 3, 4},原集合也被改了!
这里 b = a
并没有复制集合,只是让 b
和 a
指向了同一个集合对象。
使用 copy()
方法(推荐)
lang1 = {"C", "C++", "Java", "Python"}
print("lang1:", lang1, "id(lang1):", id(lang1))lang2 = lang1.copy()
print("lang2:", lang2, "id(lang2):", id(lang2))lang1.add("PHP")
print("After updating lang1")
print("lang1:", lang1, "id(lang1):", id(lang1))
print("lang2:", lang2, "id(lang2):", id(lang2))
输出(id 不同,说明是两个独立集合):
lang1: {'Python', 'Java', 'C', 'C++'} id(lang1): 140711325235392
lang2: {'Python', 'Java', 'C', 'C++'} id(lang2): 140711325235648
After updating lang1
lang1: {'Python', 'C', 'C++', 'PHP', 'Java'} id(lang1): 140711325235392
lang2: {'Python', 'Java', 'C', 'C++'} id(lang2): 140711325235648
特点:
copy()
返回 浅拷贝。- 如果集合里有可变对象(如列表),原集合和复制集合会共享它们。
使用 set()
构造函数
original_set = {1, 2, 3, 4}
copied_set = set(original_set)print("copied set:", copied_set)copied_set.add(5)
print("copied set:", copied_set)
print("original set:", original_set)
输出:
copied set: {1, 2, 3, 4}
copied set: {1, 2, 3, 4, 5}
original set: {1, 2, 3, 4}
特点:
set(iterable)
会遍历元素重新建一个集合。- 效果等同于
copy()
,但语义上更偏向“从可迭代对象构建集合”。
使用 集合推导式(Set Comprehension)
original_set = {1, 2, 3, 4, 5}
copied_set = {x for x in original_set}
print("Copied set:", copied_set)
输出:
Copied set: {1, 2, 3, 4, 5}
特点:更灵活,可以添加条件:
copied_set = {x for x in original_set if x % 2 == 0}
print(copied_set) # {2, 4}
复制多个集合合并
s1 = {1, 2}
s2 = {3, 4}
s3 = set(s1) | s2
print(s3) # {1, 2, 3, 4}
深拷贝集合(当元素是可变对象时)
import copys1 = {1, 2, (3, 4), frozenset({5, 6})}
s2 = copy.deepcopy(s1)
print(s1 == s2) # True
print(id(s1) == id(s2)) # False
快速生成副本并转换
s = {1, 2, 3}
list_copy = list(s) # 转成列表
tuple_copy = tuple(s) # 转成元组
集合运算符
集合运算符的意义
Python 中的集合运算符是对数学集合论运算的实现。它们的作用是:
- 组合多个集合(并集)
- 找出共有元素(交集)
- 找出差异(差集)
- 找出独有部分(对称差)
- 判断集合关系(子集、超集)
优点:写法简洁、效率高,很多场景比列表/字典更直观。
四大基础集合运算符
-
并集:
|
或union()
-
定义:包含两个集合中所有唯一元素。
-
语法:
A | B A.union(B)
-
图解:相当于数学的 A∪BA∪BA∪B。
-
示例:
set1 = {1, 2, 3} set2 = {3, 4, 5} print(set1 | set2) # {1, 2, 3, 4, 5} print(set1.union(set2)) # {1, 2, 3, 4, 5}
-
-
交集:
&
或intersection()
-
定义:包含两个集合中都存在的元素。
-
语法:
A & B A.intersection(B)
-
图解:相当于数学的 A∩BA∩BA∩B。
-
示例:
set1 = {1, 2, 3} set2 = {3, 4, 5} print(set1 & set2) # {3} print(set1.intersection(set2)) # {3}
-
-
差集:
-
或difference()
-
定义:集合 A 中有但 B 中没有的元素。
-
语法:
A - B A.difference(B)
-
注意:差集是 有方向的,
A - B != B - A
。 -
图解:相当于数学的 A−BA−BA−B。
-
示例:
set1 = {1, 2, 3} set2 = {3, 4, 5} print(set1 - set2) # {1, 2} print(set2 - set1) # {4, 5}
-
-
对称差:
^
或symmetric_difference()
-
定义:属于 A 或 B,但不同时属于两者。
-
语法:
A ^ B A.symmetric_difference(B)
-
图解:相当于数学的 AΔBAΔBAΔB,等价于
(A - B) ∪ (B - A)
。 -
示例:
set1 = {1, 2, 3} set2 = {3, 4, 5} print(set1 ^ set2) # {1, 2, 4, 5} print(set1.symmetric_difference(set2)) # {1, 2, 4, 5}
-
子集、超集、相等关系运算
-
子集:
<=
或issubset()
-
定义:A 的所有元素都在 B 中。
-
语法:
A <= B A.issubset(B)
-
示例:
a = {1, 2} b = {1, 2, 3} print(a <= b) # True print(a.issubset(b)) # True
-
-
真子集:
<
-
定义:A 是 B 的子集,但 A ≠ B。
-
示例:
a = {1, 2} b = {1, 2, 3} print(a < b) # True print(b < a) # False
-
-
超集:
>=
或issuperset()
-
定义:A 包含 B 的所有元素。
-
示例:
a = {1, 2, 3} b = {1, 2} print(a >= b) # True print(a.issuperset(b)) # True
-
-
真超集:
>
-
定义:A 是 B 的超集,且 A ≠ B。
-
示例:
a = {1, 2, 3} b = {1, 2} print(a > b) # True
-
-
相等:
==
-
定义:A 和 B 含有相同元素(顺序不重要)。
-
示例:
a = {1, 2, 3} b = {3, 2, 1} print(a == b) # True
-
高级运算与技巧
-
多集合运算
s1 = {1, 2, 3} s2 = {2, 3, 4} s3 = {3, 4, 5} print(s1 | s2 | s3) # 并集:{1, 2, 3, 4, 5} print(s1 & s2 & s3) # 交集:{3}
-
不相交测试:
isdisjoint()
a = {1, 2} b = {3, 4} print(a.isdisjoint(b)) # True(完全没有交集)
-
集合运算的“惰性”写法(链式)
print(({1, 2, 3} | {2, 3, 4}) & {3, 4, 5}) # {3, 4}
集合运算符一览表
运算 | 符号 | 方法 | 说明 |
---|---|---|---|
并集 | `A | B` | A.union(B) |
交集 | A & B | A.intersection(B) | A ∩ B,共同元素 |
差集 | A - B | A.difference(B) | A 有而 B 没有 |
对称差 | A ^ B | A.symmetric_difference(B) | 属于 A 或 B,但不同时属于 |
子集 | A <= B | A.issubset(B) | A 的元素全在 B 中 |
真子集 | A < B | —— | A 是 B 的子集,但不相等 |
超集 | A >= B | A.issuperset(B) | A 包含 B 的所有元素 |
真超集 | A > B | —— | A 是 B 的超集,但不相等 |
相等 | A == B | —— | 集合元素完全相同 |
不相交 | —— | A.isdisjoint(B) | A 和 B 没有公共元素 |
集合方法
集合 (set):无序、元素唯一、可变(元素必须可哈希,例如数字、字符串、元组)。
用途:去重、成员测试、集合运算(并、交、差、对称差)。
两种集合类型:
set
—— 可变集合。frozenset
—— 不可变集合。
Python 提供了 三大类方法:
- 添加和删除元素
- 集合运算(更新/返回新集合)
- 关系测试和工具方法
添加和删除元素方法
方法 | 说明 | 示例 |
---|---|---|
add(elem) | 添加单个元素 | s.add(10) |
clear() | 清空集合 | s.clear() |
copy() | 返回集合的浅拷贝 | s2 = s.copy() |
discard(elem) | 删除元素,如果不存在不会报错 | s.discard(99) |
remove(elem) | 删除元素,不存在会报错 KeyError | s.remove(2) |
pop() | 随机删除并返回一个元素 | x = s.pop() |
代码示例:
s = {1, 2, 3}
s.add(4) # {1, 2, 3, 4}
s.discard(10) # 不报错
try:s.remove(10) # KeyError
except KeyError:print("元素不存在!")
print(s.pop()) # 随机弹出一个元素
s.clear() # 变成空集合 set()
注意:
discard
vsremove
:推荐用discard
,更安全。pop()
是随机的,不要依赖返回顺序。
集合运算方法(返回新集合)
这些方法不会修改原集合,而是返回一个新集合。
方法 | 说明 | 示例 |
---|---|---|
union(other) | 并集 | {1,2}.union({2,3}) → {1,2,3} |
intersection(other) | 交集 | {1,2,3}.intersection({2,3,4}) → {2,3} |
difference(other) | 差集 | {1,2,3}.difference({2}) → {1,3} |
symmetric_difference(other) | 对称差 | {1,2,3}.symmetric_difference({3,4}) → {1,2,4} |
代码示例:
a = {1, 2, 3}
b = {3, 4, 5}
print(a.union(b)) # {1, 2, 3, 4, 5}
print(a.intersection(b)) # {3}
print(a.difference(b)) # {1, 2}
print(a.symmetric_difference(b)) # {1, 2, 4, 5}
集合运算方法(原地更新)
这些方法会 修改原集合,相当于“就地操作”。
方法 | 说明 | 示例 |
---|---|---|
update(other) | 并集更新(相当于 ` | =`) |
intersection_update(other) | 交集更新(相当于 &= ) | a.intersection_update(b) |
difference_update(other) | 差集更新(相当于 -= ) | a.difference_update(b) |
symmetric_difference_update(other) | 对称差更新(相当于 ^= ) | a.symmetric_difference_update(b) |
代码示例:
a = {1, 2, 3}
b = {3, 4, 5}a.update(b) # a = {1, 2, 3, 4, 5}
a.intersection_update({2, 3}) # a = {2, 3}
a.difference_update({2}) # a = {3}
a.symmetric_difference_update({3, 10}) # a = {10}
注意:
update
系方法会 改变原集合,而不是返回新集合。- 如果不想破坏原集合,建议用
union()
等非更新方法。
关系与测试方法
方法 | 说明 | 示例 |
---|---|---|
issubset(other) | 是否子集 | {1,2}.issubset({1,2,3}) → True |
issuperset(other) | 是否超集 | {1,2,3}.issuperset({1,2}) → True |
isdisjoint(other) | 是否无交集 | {1,2}.isdisjoint({3,4}) → True |
代码示例:
a = {1, 2}
b = {1, 2, 3}
c = {4, 5}print(a.issubset(b)) # True
print(b.issuperset(a)) # True
print(a.isdisjoint(c)) # True
冻结集合
什么是冻结集合(frozenset)
- 定义:
frozenset
是 Python 内置的不可变集合类型。 - 特性:
- 与普通集合
set
一样,元素唯一、无序。 - 不可变(immutable) —— 创建后不能修改,不能添加或删除元素。
- 因为不可变,
frozenset
可以作为字典的键 或 另一个集合的元素,而普通集合set
不行。
- 与普通集合
这就是它和 set
最大的区别:set
可变,frozenset
不可变。
创建冻结集合
冻结集合通过内置函数 frozenset() 来创建。
# 从可迭代对象创建
f1 = frozenset([1, 2, 3, 4])
print(f1) # frozenset({1, 2, 3, 4})# 从集合创建
s = {5, 6, 7}
f2 = frozenset(s)
print(f2) # frozenset({5, 6, 7})# 空冻结集合
f3 = frozenset()
print(f3) # frozenset()
冻结集合的不可变性
f = frozenset([1, 2, 3])# 不能添加
# f.add(4) # AttributeError: 'frozenset' object has no attribute 'add'# 不能删除
# f.remove(2) # AttributeError# 可以正常遍历
for i in f:print(i)# 可以用作字典键
d = {f: "hello"}
print(d) # {frozenset({1, 2, 3}): 'hello'}
frozenset 支持的方法
虽然它不能修改自身,但支持 大多数集合运算,会返回新的 frozenset
。
方法 | 描述 | 示例 |
---|---|---|
copy() | 返回自身(因为不可变,相当于原对象) | f.copy() |
union(other) | 并集,返回新 frozenset | f1.union(f2) |
intersection(other) | 交集 | f1.intersection(f2) |
difference(other) | 差集 | f1.difference(f2) |
symmetric_difference(other) | 对称差 | f1.symmetric_difference(f2) |
issubset(other) | 是否是子集 | f1.issubset(f2) |
issuperset(other) | 是否是超集 | f1.issuperset(f2) |
isdisjoint(other) | 是否没有交集 | f1.isdisjoint(f2) |
注意:像 add()
、remove()
、clear()
、update()
这些修改集合的方法 frozenset 不支持。
frozenset 与 set 的区别总结
特性 | set | frozenset |
---|---|---|
可变性 | 可变 | 不可变 |
是否可哈希 | 不能做字典键 | 可以做字典键 |
是否能修改 | 支持 add/remove/update | 不能修改 |
支持运算 | 并、交、差、对称差 | 并、交、差、对称差 |
frozenset 的典型应用场景
-
作为字典键
graph = {frozenset([1, 2]): "edge between 1 and 2",frozenset([2, 3]): "edge between 2 and 3" } print(graph[frozenset([1, 2])]) # edge between 1 and 2
-
作为集合的元素
s = {frozenset([1, 2]), frozenset([3, 4])} print(s) # {frozenset({1, 2}), frozenset({3, 4})}
-
保持数据安全(不可变,防止意外修改)。