集合基础

Python 中的集合(set)本质是一个无序、不重复的元素集合。集合的声明和初始化可以通过以下方式实现:

# 使用花括号创建(注意空{}会创建字典)
s1 = {1, 2, 3, 3, 3}           # 自动去重,结果为 {1, 2, 3}

# 使用 set() 构造函数
s2 = set([1, 2, 3])            # 从列表转换
s3 = set()                     # 创建空集合
s4 = set("hello")              # 从字符串转换,结果为 {'h', 'e', 'l', 'o'}

# 集合推导式
s5 = {x for x in range(10) if x % 2 == 0}  # {0, 2, 4, 6, 8}
集合增删改查

使用内置方法可以方便地进行集合元素的增删操作:

fruits = {"apple", "banana"}

# 添加单个元素
fruits.add("orange")
print(fruits)  # {'apple', 'banana', 'orange'}

# 添加多个元素
fruits.update(["grape", "mango"])
print(fruits)

# 删除元素(元素不存在会报错)
fruits.remove("banana")

# 安全删除(元素不存在不报错)
fruits.discard("watermelon")   # 不会抛出 KeyError

# 随机弹出一个元素
popped = fruits.pop()

# 清空集合
fruits.clear()
print(fruits)  # set()
常用集合运算

Python 集合提供了丰富的数学集合运算方法:

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

# 并集
print(a | b)           # {1, 2, 3, 4, 5, 6}
print(a.union(b))

# 交集
print(a & b)           # {3, 4}
print(a.intersection(b))

# 差集(在a中但不在b中)
print(a - b)           # {1, 2}
print(a.difference(b))

# 对称差集(仅在其中一个集合中)
print(a ^ b)           # {1, 2, 5, 6}
print(a.symmetric_difference(b))

# 子集与超集判断
print({1, 2}.issubset(a))      # True
print(a.issuperset({1, 2}))    # True

# 不相交判断
print(a.isdisjoint({7, 8}))     # True
集合与列表、元组

集合与列表、元组密切相关,可以相互转换以实现不同需求:

# 列表去重(最经典的用法)
nums = [1, 2, 2, 3, 3, 3]
unique_nums = list(set(nums))
print(unique_nums)  # [1, 2, 3]

# 元组转集合
t = (1, 2, 3, 2)
s = set(t)
print(s)  # {1, 2, 3}

# 集合转有序列表
sorted_list = sorted({3, 1, 2})
print(sorted_list)  # [1, 2, 3]

# 注意:集合只能存放不可变(可哈希)元素
# valid = {1, "hello", (1, 2)}     # ✓ 合法
# invalid = {[1, 2], {"a": 1}}   # ✗ 报错,列表和字典不可哈希
冻结集合

处理需要作为字典键或集合元素的集合时,可以使用不可变版本:

# 冻结集合(frozenset)创建后不可修改
fs1 = frozenset([1, 2, 3])
fs2 = frozenset([2, 3, 4])

# 支持所有非修改性运算
print(fs1 | fs2)       # frozenset({1, 2, 3, 4})
print(fs1 & fs2)       # frozenset({2, 3})

# 可作为字典的键
registry = {
    frozenset({"read", "write"}): "管理员",
    frozenset({"read"}): "访客"
}
print(registry[frozenset({"read", "write"})])  # 管理员

# 不可修改,以下操作会报错:
# fs1.add(4)           # AttributeError
集合操作示例

集合去重和成员检测是常见操作,可以高效实现:

# 高效成员检测(O(1) 时间复杂度)
allowed = {"admin", "editor", "viewer"}

def check_permission(user_role):
    if user_role in allowed:
        return "Access granted"
    return "Access denied"

print(check_permission("admin"))     # Access granted
print(check_permission("guest"))     # Access denied

# 查找两个列表的共同元素
list_a = [1, 2, 3, 4, 5]
list_b = [4, 5, 6, 7, 8]
common = set(list_a) & set(list_b)
print(common)  # {4, 5}

# 查找仅在一个列表中出现的元素
only_in_a = set(list_a) - set(list_b)
print(only_in_a)  # {1, 2, 3}
安全集合处理

为避免运行时错误,推荐使用安全的方法操作集合:

# 安全获取元素(集合无序,通常遍历或判断存在性)
config = {"debug", "verbose", "strict"}

# 安全判断后操作
if "debug" in config:
    print("Debug mode enabled")

# 使用 try-except 处理可能的异常
tags = {"python", "coding"}
try:
    tags.remove("java")  # 元素不存在会抛出 KeyError
except KeyError:
    print("Tag not found, skipping removal")

# 安全批量操作
new_tags = {"python", "ai", "ml"}
tags.update(new_tags)  # 自动去重合并
print(tags)  # {'python', 'coding', 'ai', 'ml'}
自定义集合使用场景

结合实际场景使用集合可以加深对集合的理解:

def find_duplicates(items):
    """查找列表中的重复元素"""
    seen = set()
    duplicates = set()
    for item in items:
        if item in seen:
            duplicates.add(item)
        else:
            seen.add(item)
    return duplicates

print(find_duplicates([1, 2, 2, 3, 3, 3]))  # {2, 3}

def jaccard_similarity(set_a, set_b):
    """计算两个集合的 Jaccard 相似度"""
    intersection = len(set_a & set_b)
    union = len(set_a | set_b)
    return intersection / union if union else 0.0

a = {"apple", "banana", "cherry"}
b = {"banana", "cherry", "date"}
print(f"相似度: {jaccard_similarity(a, b):.2f}")  # 相似度: 0.50
性能注意事项

集合操作在 Python 中需要特别注意性能和适用场景:

  • 成员检测优先用集合x in set 是 O(1),x in list 是 O(n)

  • 集合是无序的:如需保持顺序,考虑使用 dict.fromkeys()sorted()

  • 元素必须可哈希:列表、字典、普通集合不能作为集合元素,需用元组或 frozenset 替代

  • 集合运算比循环更高效:优先使用 &|- 等运算符而非手动遍历

以上代码示例涵盖了 Python 集合的主要概念和操作,从基础用法到高级技巧,为开发者提供了全面的参考。

更多推荐