集合(Set)

在 Python 中,集合是一个无序的对象集合,通过键而不是索引来访问元素。集合中的元素必须是可哈希的:整数、浮点数、元组和字符串是可哈希的,而列表、字典和除冻结集合外的集合则不是。

概述

Python 中集合的基本用法:

set1 = set()                   # 创建一个空集合
set1.add("cat")                 # 添加单个成员
set1.update(["dog", "mouse"])   # 添加多个成员,似于列表的 extend
set1 |= set(["doe", "horse"])   # 再添加多个成员,似于列表的 extend
if "cat" in set1:               # 成员测试
  set1.remove("cat")
# set1.remove("elephant") - 报错
set1.discard("elephant")        # 不抛出错误
print(set1)
for item in set1:               # 遍历集合
  print(item)
print("Item count:", len(set1)) # 长度测试
# set1[0]  # 报错:集合不支持索引
isempty = len(set1) == 0        # 测试是否为空
set1 = {"cat", "dog"}           # 使用大括号初始化集合(Python 2.7 及以后版本)
# set1 = {}                      # 错误:这是一个字典
set1 = set(["cat", "dog"])      # 从列表初始化集合
set2 = set(["dog", "mouse"])
set3 = set1 & set2              # 交集
set4 = set1 | set2              # 并集
set5 = set1 - set3              # 差集
set6 = set1 ^ set2              # 对称差集
issubset = set1 <= set2         # 子集测试
issuperset = set1 >= set2       # 超集测试
set7 = set1.copy()              # 浅拷贝
set7.remove("cat")
print(set7.pop())               # 移除一个任意元素
set8 = set1.copy()
set8.clear()                    # 清空集合
set9 = {x for x in range(10) if x % 2} # 集合推导式(Python 2.7 及以后版本)
print(set1, set2, set3, set4, set5, set6, set7, set8, set9, issubset, issuperset)

构造集合

可以通过将任何序列对象传递给 set 构造函数来构造集合。

set([0, 1, 2, 3])  # {0, 1, 2, 3}
set("obtuse")      # {'b', 'e', 'o', 's', 'u', 't'}

也可以通过 add 函数逐个添加元素到集合:

s = set([12, 26, 54])
s.add(32)
print(s)  # {32, 26, 12, 54}

注意,因为集合不允许重复元素,如果尝试再次添加集合中的某个成员,add 函数不会有任何效果。update 函数也是一样,它添加一组元素到集合中。

s.update([26, 12, 9, 14])
print(s)  # {32, 9, 12, 14, 54, 26}

成员测试

使用 in 运算符可以检查某个对象是否在集合中:

32 in s   # True
6 in s    # False
6 not in s  # True

还可以测试整个集合的成员资格。给定两个集合 S1S2,我们可以检查 S1 是否是 S2 的子集或超集。

s.issubset(set([32, 8, 9, 12, 14, -4, 54, 26, 19]))  # True
s.issuperset(set([9, 12]))  # True

注意,issubsetissuperset 方法也可以接受序列型作为参数:

s.issuperset([32, 9])  # True

<=>= 运算符也可以分别表示 issubsetissuperset 函数

set([4, 5, 7]) <= set([4, 5, 7, 9])  # True
set([9, 12, 15]) >= set([9, 12])      # True

与列表、元组和字符串一样,可以使用 len 函数来查找集合中的项数。

移除集合中的元素

在 Python 中,有三种方法可以从集合中移除单个元素:popremovediscard。其中,pop 方法随机移除集合中的一个元素。注意,pop 方法没有定义元素选择的行为。

s = set([1, 2, 3, 4, 5, 6])
s.pop()  # 移除一个元素
print(s)  # 输出:set([2, 3, 4, 5, 6])

我们也可以使用 remove 方法来移除指定的元素:

s.remove(3)  # 移除元素 3
print(s)  # 输出:set([2, 4, 5, 6])

然而,如果你试图移除一个不存在于集合中的元素,remove 方法会抛出 KeyError 错误

s.remove(9)  # 报错:KeyError: 9

如果你希望避免这种错误,可以使用 discard 方法。它的功能和 remove 相同,但是如果元素不存在,它不会抛出错误

s.discard(9)  # 不抛出错误
print(s)  # 输出:set([2, 4, 5, 6])

此外,我们还有一个用于移除集合中所有元素的操作 clear

s.clear()  # 清空集合
print(s)  # 输出:set([])

遍历集合

我们可以使用循环遍历集合中的每个元素。然而,由于集合是无序的,所以无法确定遍历的顺序。

s = set("blerg")
for n in s:
    print(n, "", end="")
# 输出:r b e l g

集合操作

Python 允许我们执行所有标准的数学集合操作,使用集合成员。每个集合操作有两种形式:一种是 s1.function(s2),它会返回一个新的集合;另一种是 s1.function_update(s2),它会修改集合 s1,使其成为 s1s2 的“函数”结果。

交集(Intersection)

交集是两个集合的共同元素。

s1 = set([4, 6, 9])
s2 = set([1, 6, 8])
print(s1.intersection(s2))  # 输出:{6}
print(s1 & s2)              # 输出:{6}
s1.intersection_update(s2)
print(s1)                   # 输出:{6}

并集(Union)

并集是两个集合的合并。任何在 s1s2 中的元素都会出现在并集中。

s1 = set([4, 6, 9])
s2 = set([1, 6, 8])
print(s1.union(s2))  # 输出:{1, 4, 6, 8, 9}
print(s1 | s2)       # 输出:{1, 4, 6, 8, 9}

对称差集(Symmetric Difference)

对称差集是两个集合中独有的元素,存在于其中一个集合中但不在两个集合中。

s1 = set([4, 6, 9])
s2 = set([1, 6, 8])
print(s1.symmetric_difference(s2))  # 输出:{8, 1, 4, 9}
print(s1 ^ s2)                      # 输出:{8, 1, 4, 9}
s1.symmetric_difference_update(s2)
print(s1)                           # 输出:{8, 1, 4, 9}

差集(Set Difference)

差集是存在于 s1 中但不在 s2 中的元素。

s1 = set([4, 6, 9])
s2 = set([1, 6, 8])
print(s1.difference(s2))  # 输出:{9, 4}
print(s1 - s2)            # 输出:{9, 4}
s1.difference_update(s2)
print(s1)                 # 输出:{9, 4}

多个集合操作

从 Python 2.6 开始,集合的 unionintersectiondifference 操作可以接受多个输入集合。

s1 = set([3, 6, 7, 9])
s2 = set([6, 7, 9, 10])
s3 = set([7, 9, 10, 11])
print(set.intersection(s1, s2, s3))  # 输出:{9, 7}

冻结集合(frozenset)

冻结集合与普通集合非常相似,区别在于它是不可变的——一旦创建,元素不能被修改。由于不可变,冻结集合也是可哈希的,因此可以作为其他集合的成员或字典的键。冻结集合与普通集合有相同的函数,除了修改内容的函数(如 updateremovepop 等)不可用。

fs = frozenset([2, 3, 4])
s1 = set([fs, 4, 5, 6])
print(s1)  # 输出:{4, frozenset([2, 3, 4]), 6, 5}
print(fs.intersection(s1))  # 输出:frozenset([4])
fs.add(6)  # 报错:AttributeError: 'frozenset' object has no attribute 'add'

练习

  1. 创建集合 {'cat', 1, 2, 3},命名为 s
  2. 创建集合 {'c', 'a', 't', '1', '2', '3'}
  3. 创建冻结集合 {'cat', 1, 2, 3},命名为 fs
  4. 创建一个包含冻结集合 fs 的集合,应该是 {frozenset({'cat', 2, 3, 1})}
最后修改: 2025年01月30日 星期四 23:43