人人都会AI编程

8.4 集合:去重原理、集合运算、适用场景

更新时间:2026-07-12

集合(set)是 Python 内置的数据结构之一,和数学里的集合概念很像:无序、不重复的元素汇集。它的底层实现基于哈希表,因此具有高效的成员检测和去重能力。掌握集合,会让很多数据处理任务变得格外简洁。


去重原理

集合最核心的特性就是元素唯一性。当你把一个序列传给 set() 时,重复的元素会被自动去除。这个“去重”不是靠循环比较,而是依赖哈希表

  • 哈希值决定身份:集合在存储元素前,会先调用 hash() 函数计算该元素的哈希值。如果哈希值相同且 == 比较也相等(考虑到哈希冲突),就认为是同一个元素,不会重复添加。
  • 对元素的要求:正因为依赖哈希,集合的元素必须是不可变(hashable)对象。数字、字符串、元组可以放入集合;列表、字典、集合本身则不行,因为它们可变,无法可靠计算哈希值。
  • 无序性:哈希表不保证插入顺序,所以集合没有索引,也不能切片。如果你需要保持顺序且去重,可以用 dict.fromkeys(seq).keys()(Python 3.7+ 字典保序)或直接保留原序的手动循环。

实际用法很简单:

nums = [3, 1, 2, 1, 3, 4]
unique_nums = set(nums)   # {1, 2, 3, 4}

这个操作的时间复杂度接近 O(n),远比手动双层循环高效。


集合运算

集合支持数学中的典型集合操作,既可以通过方法,也可以通过运算符完成,代码可读性很高。

| 数学概念 | 运算符 | 方法 | 说明 |
|---------|--------|------|------|
| 并集 | \| | union() | 返回两个集合中所有元素(去重) |
| 交集 | & | intersection() | 返回两个集合中共同存在的元素 |
| 差集 | - | difference() | 返回属于第一个集合、但不属于第二个的元素 |
| 对称差集 | ^ | symmetric_difference() | 返回只出现在其中一个集合中的元素(不同时在两个集合中) |

示例:

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a | b)   # {1, 2, 3, 4, 5, 6}
print(a & b)   # {3, 4}
print(a - b)   # {1, 2}
print(a ^ b)   # {1, 2, 5, 6}

这些运算符也可以和赋值结合,实现原地更新(如 a |= b 相当于 a.update(b))。

除上述基础运算,集合还提供:

  • add(elem):添加单个元素。
  • remove(elem) / discard(elem):删除元素,前者在元素不存在时抛出 KeyError,后者不报错。
  • pop():随机弹出某个元素(因为无序,所以无法预测)。
  • issubset() / issuperset():判断子集/超集关系。
  • isdisjoint():判断两个集合是否没有交集。

适用场景

集合在“去重”和“关系比较”方面的优势,使它天然适合以下场景:

  1. 快速去重

将列表转为集合再转回列表,是最常见的去重写法:

   unique_list = list(set(original_list))
   

注意:这样会丢失原始顺序,如果顺序重要,可用 sorted(set(...), key=original_list.index) 或利用字典键保序。

  1. 成员检查

判断元素是否存在,集合比列表快得多(O(1) vs O(n))。当数据量大且需要反复in判断时,应优先考虑用集合或字典存储数据。

  1. 交集/差集比较
  • 找出两个列表的共同元素:set(list1) & set(list2)
  • 找出一个列表中不在另一个列表的元素:set(list1) - set(list2)
  • 这种写法比嵌套循环清晰高效得多,常用于权限校验、标签筛选、数据对账等业务。
  1. 去除重复字符串或单词

分词后想统计独特词汇:unique_words = set(text.split())

  1. 缓存访问记录(如已处理 ID)

爬虫已经爬过的 URL、已发送通知的用户 ID 等,可以用集合保存,每次判断 if id in processed_ids 就能快速跳过。

  1. 数学集合模型

需要实现数学概念集合操作时,直接用 Python 集合映射,代码和公式非常接近。


补充:不可变集合 frozenset

frozenset 是集合的不可变版本。一旦创建,不能增删元素。它主要用于:

  • 作为另一个集合的元素(因为 frozenset 可哈希)。
  • 作为字典的键。
  • 在需要保证集合内容不会被意外修改的场景。
fs = frozenset([1, 2, 3])
d = {fs: "value"}   # 合法

总体而言,集合是 Python 数据处理工具链中的一把“轻巧快刀”,善用它可以大幅减少循环和条件判断,让代码更加简洁、直观、高效。