Appearance
10|集合
集合是无序、不重复的元素集合。它的核心价值是去重和集合运算。判断成员是否存在、求交集并集差集、过滤重复项——这些操作在集合上的效率远高于列表。
一、创建集合
python
# 字面量(注意:空 {} 是字典,不是集合)
tags = {"python", "go", "shell"}
# 空集合
empty = set()
# 从列表/元组/字符串创建
set([1, 2, 2, 3]) # {1, 2, 3},自动去重
set("hello") # {'h', 'e', 'l', 'o'}集合里的元素必须是不可变类型(可哈希),和字典的键要求一致。列表、字典不能作为集合的元素。
二、增删改查
python
s = {1, 2, 3}
# 添加
s.add(4) # {1, 2, 3, 4}
s.update([5, 6]) # {1, 2, 3, 4, 5, 6},批量添加
# 删除
s.remove(3) # 删除 3,不存在抛 KeyError
s.discard(10) # 删除 10,不存在不报错
s.pop() # 随机删除并返回一个元素
s.clear() # 清空remove() 和 discard() 的区别:不确定元素是否存在时,用 discard() 更安全。
三、集合运算
python
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
a | b # {1, 2, 3, 4, 5, 6},并集
a & b # {3, 4},交集
a - b # {1, 2},差集(在 a 中但不在 b 中)
b - a # {5, 6},差集(在 b 中但不在 a 中)
a ^ b # {1, 2, 5, 6},对称差集(只在其中一个集合中)也可以用方法:
python
a.union(b) # 并集
a.intersection(b) # 交集
a.difference(b) # 差集
a.symmetric_difference(b) # 对称差集方法支持传入任意可迭代对象,而运算符要求两边都是集合:
python
a.union([5, 6]) # 可以,列表也能传
a | [5, 6] # TypeError四、判断关系
python
a = {1, 2}
b = {1, 2, 3, 4}
a < b # True,a 是 b 的真子集
a <= b # True,a 是 b 的子集
b > a # True,b 是 a 的真超集
a.isdisjoint({5, 6}) # True,没有共同元素五、去重
去重是集合最常见的用途:
python
items = ["a", "b", "a", "c", "b", "a"]
unique = list(set(items))
# {'a', 'b', 'c'} → 转成列表,但顺序不保证如果需要保留原顺序的去重(Python 3.7+):
python
unique = list(dict.fromkeys(items))
# ['a', 'b', 'c'],利用字典保持插入顺序的特性六、成员判断的效率
集合的成员判断(in)时间复杂度是 O(1),列表是 O(n)。数据量大时,这个差距很明显:
python
large_list = list(range(100_000))
large_set = set(large_list)
99_999 in large_list # 慢,需要遍历
99_999 in large_set # 快,直接定位需要频繁判断"某个值是否在集合中"时,先把数据转成集合。
七、frozenset
集合是可变的,不能作为字典的键或另一个集合的元素。frozenset 是不可变的集合,解决了这个问题:
python
fs = frozenset([1, 2, 3])
fs.add(4) # AttributeError: 'frozenset' object has no attribute 'add'
cache = {}
cache[fs] = "value" # 可以,frozenset 可哈希frozenset 支持所有集合运算(|, &, -, ^),但不支持增删改。
记忆锚点:集合无序不重复,元素必须不可变;add() 加单个,update() 批量;discard() 安全删除;| & - ^ 是并交差对称差;集合的 in 判断是 O(1),列表是 O(n);frozenset 是不可变集合,可作字典键。