Python 集合(set)
set(集合)是内置的可变容器:元素唯一、无序(不保证遍历顺序)、成员检测平均时间复杂度为 O(1)(依赖哈希表,极端情况下可能退化)。适合去重、交集/并集等场景。与标准库 collections 模块名易混,注意区分。
创建集合
python
numbers = {1, 2, 3, 4, 5}
fruits = {"apple", "banana", "cherry"}
# 从列表等可迭代对象去重
numbers = set([1, 2, 2, 3, 3, 3, 4])
# 字符串按字符拆分(每个字符一个元素)
letters = set("hello")
print(letters) # {'h', 'e', 'l', 'o'},注意只有一个 'l'空集合
{} 表示空字典,不是空集合。 空集合必须写 set():
python
empty = set() # 空集合
not_a_set = {} # 这是 dict增删与查找
python
animals = {"cat", "dog", "bird"}
animals.add("fish")
animals.add("cat") # 已存在则不变
animals.remove("dog") # 不存在会 KeyError
animals.discard("elephant") # 不存在也不报错
x = animals.pop() # 任意弹出一个元素;空集调用会 KeyErrorremove:要求元素存在。discard:不存在时静默跳过,适合「可能没有」的场景,少写try/except。
x in s、x not in s 常用于成员判断;大循环里用 set 往往比 list 快得多。
集合运算
python
developers = {"Alice", "Bob", "Charlie"}
designers = {"Bob", "Diana", "Eve"}
print(developers | designers) # 并集
print(developers & designers) # 交集
print(developers - designers) # 差集(在 A 不在 B)
print(developers ^ designers) # 对称差(只在一方)等价方法:union、intersection、difference、symmetric_difference。方法可接受任意可迭代对象;运算符 | 两侧必须是 set(或 frozenset 等),否则可能 TypeError:
python
numbers = {1, 2, 3}
print(numbers.union([4, 5, 6])) # 可以
# numbers | [4, 5, 6] # TypeError原地更新
带 _update 后缀的方法会就地修改集合:
python
tags = {"python", "programming"}
tags.update(["web", "backend", "api"])
allowed = {"python", "web", "mobile"}
tags.intersection_update(allowed)
tags = {"python", "web", "mobile", "backend"}
tags.difference_update({"mobile", "backend"})另有 |=、&=、-=、^= 等增强赋值形式。
实用示例
python
# 列表去重(不保证顺序;要保序见文末)
user_ids = [101, 102, 101, 103, 102, 104]
unique_ids = list(set(user_ids))
# 共同兴趣
a = {"python", "golang", "javascript"}
b = {"python", "java", "javascript"}
print(a & b)
# 唯一访客
visitors = set()
visitors.add("user_123")
visitors.add("user_456")
visitors.add("user_123")
print(len(visitors))大批量 in 判断时,把合法 id 放进 set 再过滤,通常比 list 快很多。
frozenset(不可变集合)
frozenset 不可修改,可哈希,可作 dict 的键或放进另一个 set:
python
immutable = frozenset([1, 2, 3])
cache = {frozenset(["python", "tutorial"]): "ok"}
nested = {frozenset([1, 2]), frozenset([3, 4])}集合推导式
python
squares = {x**2 for x in range(10)}
text = "the quick brown fox jumps over the lazy dog"
words = {w for w in text.split()}
evens_squared = {x**2 for x in range(1, 11) if x % 2 == 0}元素必须「可哈希」
set 里只能放可哈希(hashable)对象:int、str、tuple(元素都可哈希时)等。list、dict、set 可变,不能作为 set 的元素:
python
# {[1, 2, 3]} # TypeError: unhashable type: 'list'
good = {(1, 2, 3)} # 元组可哈希顺序与「有序去重」
集合不记录插入顺序。若既要唯一又要顺序,可用 Python 3.7+ 字典的插入顺序特性:
python
ordered_unique = list(dict.fromkeys([3, 1, 2, 1, 3, 2]))
print(ordered_unique) # [3, 1, 2]小结
set | list | |
|---|---|---|
| 重复元素 | 自动去重 | 允许重复 |
| 顺序 | 不保证 | 保证 |
in 平均 | 约 O(1) | O(n) |
集合占用内存通常比紧凑列表更大,需在「速度」与「内存」间权衡。