脚本专家 发表于 2026-6-15 11:00:01

Python集合运算深入:并集、交集、差集、对称差集用法与实战

Python 的集合(set)不仅支持去重,还内置了四种基本集合运算:并集、交集、差集和对称差集。这些运算对应数学中的集合论,但在代码中只需要一个运算符或方法即可完成,且性能极高(基于哈希表实现)。本文会用实际案例逐一讲解每种运算的运算符、方法、原地操作以及适用场景,最后给出一个好友推荐系统的实现示例。

一、并集(Union):合并所有元素并去重

并集返回两个(或多个)集合中的所有元素,自动去重。Python 提供两种方式:
- 运算符 `|`:两边都必须是集合。
- 方法 `union()`:可以接受任意可迭代对象(列表、元组、range、字典的键等)。

示例:

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b)# {1, 2, 3, 4, 5, 6}
print(a.union())# {1, 2, 3, 4, 5},参数是列表


当需要合并多个集合时,可以用链式 `|` 或 `union()` 传入多个参数:

a = {1, 2}
b = {2, 3}
c = {3, 4}
result = a | b | c# {1, 2, 3, 4}
result = a.union(b, c)# 同上


原地操作 `|=` 会直接修改原集合:

a = {1, 2, 3}
b = {3, 4, 5}
a |= b# a 变为 {1, 2, 3, 4, 5},原对象被修改


实战:合并多个数据源的用户邮箱。

email_sources = {
    'web': {'alice@test.com', 'bob@test.com'},
    'mobile': {'bob@test.com', 'david@test.com'},
    'api': {'charlie@test.com', 'frank@test.com'},
}
all_emails = set().union(*email_sources.values())
print(all_emails)# {'alice', 'bob', 'charlie', 'david', 'frank'}


二、交集(Intersection):找出共有元素

交集返回同时存在于所有集合中的元素。运算符 `&` 要求两边都是集合,方法 `intersection()` 可接受可迭代对象。

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a & b)# {3, 4}
print(a.intersection())# {3, 4}


多个集合求交集:

a = {1, 2, 3, 4, 5}
b = {2, 3, 4, 5, 6}
c = {3, 4, 5, 6, 7}
print(a & b & c)# {3, 4, 5}
print(a.intersection(b, c))# 同上


原地操作 `&=` 会修改原集合。

实战:找同时满足多个条件的用户。

purchased = {'alice', 'bob', 'charlie'}
subscribed = {'alice', 'charlie', 'david'}
reviewed = {'alice', 'david', 'frank'}
loyal = purchased & subscribed & reviewed
print(loyal)# {'alice'}


三、差集(Difference):获取独有的元素

差集返回前一个集合中去除与后一个集合共有元素后的剩余元素,**不对称**。运算符 `-` 要求两边都是集合,方法 `difference()` 可接受可迭代对象。

a = {1, 2, 3, 4, 5}
b = {4, 5, 6, 7, 8}
print(a - b)# {1, 2, 3}
print(b - a)# {6, 7, 8}
print(a.difference())# {1, 2, 3}


多个集合求差集时,按顺序连续减去:

a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
b = {1, 2, 3}
c = {4, 5}
result = a - b - c# 或 a.difference(b, c)
print(result)# {6, 7, 8, 9, 10}


原地操作 `-=`。

实战:权限管理——排除被禁用的操作。

all_perms = {'read', 'write', 'delete', 'admin', 'export', 'import'}
role_editor = {'read', 'write', 'export'}
forbidden = {'delete', 'admin', 'import'}
actual = role_editor - forbidden
print(actual)# {'read', 'write', 'export'}


四、对称差集(Symmetric Difference):找出仅属于一个集合的元素

对称差集返回只出现在其中一个集合中的元素,排除共有部分。运算符 `^` 要求两边都是集合,方法 `symmetric_difference()` 只接受一个参数(不能多个)。

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a ^ b)# {1, 2, 5, 6}
print(a.symmetric_difference(b))# 同上


验证对称等价式:`a ^ b == (a - b) | (b - a) == (a | b) - (a & b)`。

原地操作 `^=`。

实战:比较两个版本的功能变更。

v1 = {'login', 'register', 'profile', 'search', 'cart'}
v2 = {'login', 'register', 'profile', 'search', 'cart', 'chat', 'analytics'}
changes = v1 ^ v2
print(changes)# {'chat', 'analytics'}
added = v2 - v1
removed = v1 - v2


五、运算符 vs 方法:如何选择

- 运算符(| & - ^):代码简洁,但操作数都必须是集合。
- 方法(union, intersection, difference, symmetric_difference):可以接受列表、元组等可迭代对象,而且 `union` 和 `intersection` 支持多参数。
- 原地运算符(|= &= -= ^=)修改原集合,建议仅在需要性能优化(如大数据量循环)时使用,通常应优先创建新对象以避免副作用。

六、性能对比:集合 vs 列表

集合运算基于哈希表,时间复杂度远低于列表的线性搜索。例如,对 10000 个元素求交集,集合比列表快 100 倍以上。实际测试中,集合运算瞬间完成,而列表推导式则需要数百倍时间。因此,在需要频繁判断成员关系的场景中,应优先使用集合。

七、综合实战:好友推荐系统

假设用户数据如下,推荐规则:如果 A 和 B 不是好友,但有共同好友,则推荐 B 给 A。

class FriendRecommender:
    def __init__(self, friendships):
      # friendships: dict of username -> set of friends
      self.friends = friendships

    def recommend(self, user):
      if user not in self.friends:
            return set()
      user_friends = self.friends
      candidates = set()
      for friend in user_friends:
            # 每个好友的好友(排除自己和已好友)
            candidates |= self.friends - user_friends - {user}
      # 按共同好友数排序
      from collections import Counter
      common_counts = Counter()
      for candidate in candidates:
            common = user_friends & self.friends
            common_counts = len(common)
      # 返回按共同好友数降序排列的推荐列表
      return common_counts.most_common()

# 示例数据
friendships = {
    'Alice': {'Bob', 'Charlie', 'David'},
    'Bob': {'Alice', 'Charlie', 'Eve'},
    'Charlie': {'Alice', 'Bob', 'Frank'},
    'David': {'Alice'},
    'Eve': {'Bob'},
    'Frank': {'Charlie'},
}
recommender = FriendRecommender(friendships)
print(recommender.recommend('Alice'))


此实现利用并集、差集、交集高效找出候选人和计算共同好友数。

八、注意事项

- 运算符两边必须都是集合,否则会抛出 TypeError;方法则可以接受任何可迭代对象。
- 运算符优先级:`-` 优先级高于 `|` 和 `&`,但低于比较运算符,必要时加括号。
- 对称差集方法只能传一个参数;多个集合的对称差需用链式 `^`。
- 集合元素必须是不可变类型(如数字、字符串、元组),不能包含列表或集合,否则无法参与运算。

掌握集合的四类运算,可以大幅简化数据处理代码,尤其适用于去重、筛选、差异对比等场景。建议优先使用方法以避免类型转换,在性能敏感处使用原地操作。

热心网友7 发表于 2026-6-15 11:10:00

Re: Python集合运算深入:并集、交集、差集、对称差集用法与实战

感谢分享!写得非常清晰,尤其是权限管理和版本对比的例子很有启发性。我自己之前一直只习惯用 `|` 和 `&`,看到 `difference()` 可以接受可迭代对象这点确实方便很多。想问一下,如果集合里的元素是自定义对象(比如需要重写 `__hash__` 和 `__eq__`),这些运算还能正常用吗?

热心网友7 发表于 2026-6-16 17:25:00

Re: Python集合运算深入:并集、交集、差集、对称差集用法与实战

感谢楼主的详细整理!一直觉得Python集合运算非常强大,但在实际工作中经常分不清 `difference` 和 `symmetric_difference`,看完这个帖子终于彻底理清了。特别喜欢你给的好友推荐和权限管理例子,直接就能套用到项目里。我补充一个小点:如果集合元素是可变对象(比如列表),记得先转换成不可变形式才能放进集合,否则会报错。再次感谢!

热心网友5 发表于 2026-6-16 20:00:00

Re: Python集合运算深入:并集、交集、差集、对称差集用法与实战

非常感谢楼主的详细讲解,把集合的四种运算讲得既系统又接地气,特别是每个运算都配了实战案例,直观好用。 我平时在数据清洗和用户标签处理中也常用集合运算,但很少把对称差集用到版本对比上,你这个例子让我眼前一亮——用 `^` 快速找出新增和移除的功能,再配合差集拆分 `added` 和 `removed`,逻辑非常清晰,后续做 changelog 生成就方便多了。 另外想请教一下:在做大规模好友推荐时(比如百万级用户),如果直接用 `intersection` 或 `&` 来求共同好友,会不会有内存或性能瓶颈?需不需要先用一些近似算法做剪枝,还是说 Python 集合的哈希实现能扛得住?期待楼主分享一下实际项目中的优化经验。
页: [1]
查看完整版本: Python集合运算深入:并集、交集、差集、对称差集用法与实战