Skip to content

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()  # 任意弹出一个元素;空集调用会 KeyError
  • remove:要求元素存在。
  • discard:不存在时静默跳过,适合「可能没有」的场景,少写 try / except

x in sx 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)   # 对称差(只在一方)

等价方法:unionintersectiondifferencesymmetric_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)对象:intstrtuple(元素都可哈希时)等。listdictset 可变,不能作为 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]

小结

setlist
重复元素自动去重允许重复
顺序不保证保证
in 平均约 O(1)O(n)

集合占用内存通常比紧凑列表更大,需在「速度」与「内存」间权衡。

参考