Python3 集合

在 Python 3 中,集合(Set) 是一种极其强大且高效的数据结构。它的核心特征是:无序、元素唯一、基于哈希表实现

如果说列表(List)是用来“存储顺序”的,字典(Dict)是用来“建立映射”的,那么集合(Set)就是用来 “去重”和“快速查找” 的。

下面我将从基础操作核心数学运算高频应用场景常见陷阱,为你全面解析 Python 3 的集合。


一、 创建集合

有两种创建集合的方式,但有一个极其重要的陷阱需要注意。

纯文本
# 1. 使用花括号 {} (最常用)
fruits = {"apple", "banana", "cherry"}
print(type(fruits))  # <class 'set'>

# 2. 使用 set() 构造函数 (常用于将其他可迭代对象转换为集合)
numbers = set([1, 2, 2, 3, 3, 3])
print(numbers)  # 输出: {1, 2, 3} (自动去重)

# ⚠️ 致命陷阱:如何创建空集合?
empty_dict = {}          # ❌ 这是空字典 (dict)
empty_set = set()        # ✅ 这才是空集合 (set)

二、 基本增删改查

由于集合是无序的,它不支持索引(如 my_set[0] 会报错),也不支持切片。

纯文本
my_set = {"apple", "banana"}

# 1. 添加元素
my_set.add("cherry")          # 添加单个元素
my_set.update(["orange", "grape"]) # 批量添加多个元素 (可传入任何可迭代对象)

# 2. 删除元素
my_set.remove("banana")       # 删除指定元素,如果不存在会抛出 KeyError
my_set.discard("watermelon")  # 删除指定元素,如果不存在**不会报错** (推荐)
popped_item = my_set.pop()    # 随机删除并返回一个元素 (因为集合无序)

# 3. 清空集合
my_set.clear()

三、 核心优势:数学集合运算 🌟

这是 Set 最迷人的地方。Python 允许你使用直观的运算符(或对应的方法)来执行标准的数学集合运算,且性能极高

纯文本
set_a = {1, 2, 3, 4, 5}
set_b = {4, 5, 6, 7, 8}

# 1. 交集 (Intersection):两者都有的元素
print(set_a & set_b)          # 运算符: {4, 5}
print(set_a.intersection(set_b)) # 方法

# 2. 并集 (Union):两者的所有元素(自动去重)
print(set_a | set_b)          # 运算符: {1, 2, 3, 4, 5, 6, 7, 8}
print(set_a.union(set_b))

# 3. 差集 (Difference):在 A 中但不在 B 中的元素
print(set_a - set_b)          # 运算符: {1, 2, 3}
print(set_a.difference(set_b))

# 4. 对称差集 (Symmetric Difference):只在 A 或只在 B 中的元素 (非交集部分)
print(set_a ^ set_b)          # 运算符: {1, 2, 3, 6, 7, 8}
print(set_a.symmetric_difference(set_b))

💡 提示:运算符(&, |, -, ^)只能用于两个集合之间;而方法(.intersection() 等)可以接收任何可迭代对象(如列表),更加灵活。


四、 高频实战应用场景

场景 1:极速去重 (Deduplication)

这是 Set 最常见的用途。将列表转换为集合再转回列表,即可去重。

纯文本
raw_data = [1, 2, 2, 3, 4, 4, 5]
unique_data = list(set(raw_data))
print(unique_data)  # 输出: [1, 2, 3, 4, 5] (注意:顺序可能会改变)

⚠️ 进阶技巧:如果去重后必须保持原有顺序,不要用 Set,请用字典(Python 3.7+ 字典保持插入顺序):

纯文本
unique_ordered = list(dict.fromkeys(raw_data))

场景 2:O(1) 极速成员检查 (Membership Testing)

当需要频繁检查某个元素是否存在于大量数据中时,绝对不要用 List,一定要用 Set

纯文本
# 假设有 100 万个用户 ID
valid_ids_list = [1001, 1002, ..., 999999] # 查找时间复杂度: O(n)
valid_ids_set = set(valid_ids_list)        # 查找时间复杂度: O(1)

user_id = 500000

# ❌ 慢:需要遍历列表
if user_id in valid_ids_list: 
    pass

# ✅ 快:基于哈希表直接定位,瞬间完成
if user_id in valid_ids_set:
    pass

场景 3:集合推导式 (Set Comprehension)

与列表推导式语法类似,但使用花括号,生成的是集合。

纯文本
# 获取 0-9 中所有偶数的平方,并自动去重
squares = {x**2 for x in range(10) if x % 2 == 0}
print(squares)  # 输出: {0, 16, 64, 36, 4} (无序)

五、 不可变集合:frozenset

普通的 set 是可变的(Mutable),因此它不能作为字典的键 (Key),也不能放在另一个集合中
如果你需要一个不可变的集合,可以使用 frozenset

纯文本
# 创建冻结集合
frozen = frozenset([1, 2, 3])

# frozen.add(4)  # ❌ AttributeError: 'frozenset' object has no attribute 'add'

# ✅ 应用场景 1:作为字典的键
permissions = {
    frozenset(["read", "write"]): "Editor",
    frozenset(["read"]): "Viewer"
}
print(permissions[frozenset(["read"])])  # 输出: Viewer

# ✅ 应用场景 2:作为集合的元素 (集合的集合)
set_of_sets = {frozenset([1, 2]), frozenset([3, 4])}

六、 常见陷阱与最佳实践

1. 集合的元素必须是“可哈希的” (Hashable)

因为集合底层是哈希表,所以放入集合的元素必须是不可变的(如整数、字符串、元组)。不能将列表、字典或其他普通集合放入集合中

纯文本
# ❌ TypeError: unhashable type: 'list'
my_set = {1, 2, [3, 4]} 

# ✅ 正确做法:将内部列表转为元组
my_set = {1, 2, (3, 4)}

2. 性能对比总结 (何时使用什么?)

需求推荐数据结构原因
需要保持顺序,允许重复list有序,支持索引
需要键值对映射dict快速通过 Key 查找 Value
需要快速判断“是否存在” (in)set哈希查找,O(1) 时间复杂度
需要去重或进行交/并/差集运算set内置数学运算,代码极简且高效

总结

Python 的集合(Set)不仅仅是一个“去重工具”,它是处理唯一性关系运算的利器。记住两个黄金法则:

  1. 需要极速查找 (in) 时,把列表转成集合。
  2. 需要比较两组数据的重叠或差异时,毫不犹豫地使用 &, |, -, ^

你目前是否有处理大量数据去重,或者需要比对两个列表差异的具体需求?我可以帮你用 Set 写出最优雅的代码!