Python 中多个集合的对称差集

2025年3月17日 | 阅读 8 分钟

本文将讨论使用各种方法在 Python 中查找多个集合的对称差集的问题。

Python 中的集合

在 Python 中,集合是包含在大括号 {} 中的无序、可变且元素唯一的集合。集合中的每个元素都必须是可哈希的,这意味着它可以被唯一标识,并且是不可变的,这意味着一旦添加到集合中就无法更改。集合通常用于需要成员资格测试、去重和无序集合的任务。

对称差集

两个集合之间的对称差集是指一个集合,其中包含存在于其中一个集合中但不两个集合都存在的元素。换句话说,它是每个集合特有的项目集合,排除了两个集合共有的项目。

可以使用 ^ (插入符号) 运算符或 `symmetric_difference()` 方法轻松找到两个集合之间的对称差集。

以下是查找两个集合对称差集的示例

集合 set1 和 set2 之间的对称差集包含 {1, 2, 3, 6, 7, 8},这些元素存在于 set1 或 set2 中,但不在两者中。

注意:在计算对称差集时,原始集合 set1 和 set2 不会被修改。相反,会返回一个包含结果的新集合。

多个集合的对称差集

在 Python 中,有多种方法可以计算多个集合的对称差集

例如

如果输入是

输出应该是

Symmetric Difference: {1, 2, 3, 10}

解释 - 1、2 和 3 仅存在于 set1 中,而 10 仅存在于 set4 中。

现在让我们讨论查找多个集合之间对称差集的各种方法

方法 1 - 使用 `Collections` 中的 `Counter`

在 Python 中,您可以使用 `collections` 模块中的 `Counter` 来计算多个集合的对称差集

输出

Set difference: {10, 1, 2, 3}

说明

`Counter` 类只接受一个参数(一个可迭代对象)。但是我们有四个集合,为此,我们使用了 `itertools` 中的 **`chain` 函数**将所有集合合并为一个可迭代对象,并将其传递给 `Counter` 类来计算每个元素的出现次数。

`chain` 函数的语法是: **`itertools.chain(*iterables)`**

输出

Single Iter: 1 2 3 4 5 4 5 6 7 8 5 6 7 8 9 6 7 8 9 10

**`Counter`** - `Counter` 是 Python `collections` 模块中的一个内置类,它提供了一种实用方法来计算元素在集合(如列表、元组或字符串)中出现的次数。它专门用于计数,是 `dict` 类的子类。

`Counter` 的语法如下: **`collections.Counter`** **( **[**iterable-or-mapping**]** )**

输出

Each element with frequency: Counter({5: 3, 6: 3, 7: 3, 8: 3, 4: 2, 9: 2, 1: 1, 2: 1, 3: 1, 10: 1})

在程序末尾,我们过滤出频率为 1 的元素并将其转换为集合。最后,在控制台打印结果。

方法 2 - 使用集合运算 **“并集”和“交集”**

让我们先理解一下这个想法。下面是四个集合的维恩图。

Symmetric Difference of Multiple Sets in Python

这些集合的对称差集将只包含 A、B、C 和 D 部分。要找到这一点,我们将取所有集合的并集,然后减去 (A 和 B)、(B 和 C)、(C 和 D) 以及 (A 和 D) 的交集。

并集 (A, B, C, D) = {A, B, C, D, AB, BC, CD, AD, ABC, BCD, ACD, ABD, ABCD}

交集 (A, B) = {AB, ABC, ABD, ABCD}

交集 (B, C) = {BC, ABC, BCD, ABCD}

交集 (C, D) = {CD, BCD, ACD, ABCD}

交集 (A, D) = {AD, ACD, ABD, ABCD}

对称差集 (A, B, C, D) = 并集 (A, B, C, D) - 交集 (A, B) -交集 (B, C) - 交集 (C, D) - 交集 (A, D)

对称差集 (A, B, C, D) = {A, B, C, D} # 期望输出

输出

Set difference: {10, 1, 2, 3}

此方法使用并集和交集来查找所需的并集和交集。此方法的问题在于您必须单独计算集合的交集,而这是可以避免的。您可以对程序进行一些潜在的改进,例如

将 *args 语法与 set.union() 结合使用:您可以使用 *args 语法与 `set.union(*sets)` 将集合解包到 `union()` 方法中,而不是使用 `set1.union(set2, set3, set4)` 将集合链接在一起,这可以使代码更简洁。

方法 3 - 使用 XOR (^) 运算符和集合推导式

在此方法中,我们将使用 XOR (^) 运算符来查找集合之间的对称差集,并过滤出仅存在于一个集合中的所有元素。

输出

Symmetric Difference: {10, 1, 2, 3}

说明

在上面的代码中,`symmetric_difference` 变量存储了 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}。在找到对称差集后,我们使用集合推导式过滤出仅存在于一个集合中的元素。

`sum(x in s for s in sets) == 1` 条件,它计算一个元素在所有集合中出现的次数并检查它是否等于 1。过滤后的元素存储在 `set_diff` 变量中。最后,使用带有格式化字符串的 `print()` 语句打印结果对称差集。

方法 4 - 使用并集运算符和集合推导式

在此方法中,我们将首先使用并集运算符查找所有集合中的唯一元素。然后,我们将使用集合推导式过滤出仅存在于一个集合中的元素。

输出

Symmetric Difference: {10, 1, 2, 3}

说明

此方法使用并集运算符查找唯一元素,然后过滤出仅存在于一个集合中的元素。有关进一步解释,请参阅方法 3 中的解释。

方法 5 - 使用 `functools` 中的 `reduce` 函数

在此方法中,我们将使用 `reduce` 函数查找对称差集,并使用如上所述的集合推导式过滤出仅存在于一个集合中的元素。

输出

Symmetric Difference: {10, 1, 2, 3}

说明

`reduce()` 函数与 `lambda` 函数结合使用,对 `sets` 列表中的成对集合重复应用 `symmetric_difference()` 方法,从第一个集合 (set1) 到最后一个集合 (set4)。

集合推导式过滤元素,过滤后的元素存储在 `set_diff` 中,代表对称差集。