11  集合set

11.1 集合数据类型

数学中的集合,是由一个或多个确定的元素所构成的整体,具有无序、无重复元素的性质。

Python 中的集合对象,是无序的、无重复元素的可哈希对象的组合。 Python 有 2 种集合数据类型:set(可变)和 frozenset(不可变)。

创建集合对象有 3 种方式: 1. 字面量,用 {} 包围元素,逗号分隔 2. 用 set()frozenset() 类创建,参数为可迭代对象 3. 集合推导式,类似于列表推导式,将 [] 换成 {}

# 字面量
{1, 2, 1}
{1, 2}
{1, 'a', True}
{1, 'a'}
# 元素必须是可哈希的
{'a', [1, 2]}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[3], line 2
      1 # 元素必须是可哈希的
----> 2 {'a', [1, 2]}

TypeError: unhashable type: 'list'
# set类, frozenset类
set([1, 2, 1])
{1, 2}
set('Hello')
{'H', 'e', 'l', 'o'}
set()    # 空集合
frozenset()
set()
frozenset()
# 集合推导式
{i for i in range(5)}
{0, 1, 2, 3, 4}
{2 ** i for i in range(5)}
{1, 2, 4, 8, 16}
{x ** 2 for x in [1, 1, 2]}
{1, 4}

11.2 集合运算符与方法

中学数学的集合运算(交、并、补、差)以及集合关系判断(子集、超集),可以通过运算符或方法实现:

类型 运算符 方法 含义
集合运算 | union 并集
& intersection 交集
- difference 差集
^ symmetric_difference 对称差
集合关系 == / != 是否相等/不等
< / <= issubset 是否是(真)子集
> / >= issuperset 是否是(真)超集
isdisjoint 是否不相交

超集(superset)与子集(subset)的关系

集合运算:交(intersect),并(union),差(difference)

此外,集合还支持 len()max()/min()(要求元素可比较大小)、sum()(要求元素是数值类型)、in/not in

s1 = {1, 3, 5, 7, 9}
s2 = {1, 2, 3}
print(s1 | s2)   # 并集
print(s1 & s2)   # 交集
print(s1 - s2)   # 差集
print(s1 ^ s2)   # 对称差
{1, 2, 3, 5, 7, 9}
{1, 3}
{9, 5, 7}
{2, 5, 7, 9}
s1 = {1, 3, 5}
s2 = {1, 2, 3, 4, 5}
print(s1 < s2)     # 真子集
print(s1 <= s2)    # 子集
print(s2 > s1)     # 真超集
print(s1.isdisjoint({2, 4}))  # 不相交?
True
True
True
True

11.3 set 对象的其他方法

set 是可变集合,支持以下修改操作:

s = {1, 2, 3}

s.add(4)       # 添加元素
print(s)

s.remove(2)    # 移除元素(不存在则报错)
print(s)

s.discard(10)  # 移除元素(不存在不报错)
print(s)

print(s.pop()) # 随机取出一个元素
print(s)
{1, 2, 3, 4}
{1, 3, 4}
{1, 3, 4}
1
{3, 4}
注记例:用集合去除重复元素
# 列表去重(但会丢失顺序)
nums = [1, 2, 2, 3, 3, 3, 4]
unique = list(set(nums))
print(unique)
[1, 2, 3, 4]
注记例:用集合运算筛选共同元素
# 找出两个列表中的共同元素
a = [1, 2, 3, 4, 5]
b = [4, 5, 6, 7, 8]
common = set(a) & set(b)
print(common)
{4, 5}

11.4 练习

  1. 集合的 Jaccard 系数用于衡量两个集合的相似度,定义为 J(A, B) = \dfrac{|A \cap B|}{|A \cup B|}。写一个函数 jaccard(s1, s2) 计算两个字符串的 Jaccard 系数(将字符串视为字符的集合)。

    提示:可以利用集合的 & 运算符求交集、| 运算符求并集。

def jaccard(s1, s2):
    # 将字符串转为集合,计算 Jaccard 系数
    pass

# 测试
print(jaccard('apple', 'apples'))
print(jaccard('hello', 'world'))
None
None