6.3.1 集合

Python 提供了集合类型 set,用于表示大量数据的无序集合体。集合可以由各种数据组 成,数据之间没有次序,并且互不相同。可见,Python 集合基本上就是数学中所说的集合①。

集合类型的值有两种创建方式:一种是用一对花括号将多个用逗号分隔的数据括起来; 另一种是调用函数 set(),此函数可以将字符串、列表、元组等类型的数据转换成集合类型的 数据。不管用哪种方式创建集合值,在 Python 内部都是以 set([...])的形式表示的。注意,空 集只能用 set()来创建,而不能用字面值{}表示,因为 Python 将{}用于表示空字典(见 6.3.2 节)。

下面的会话过程演示了集合类型的值的创建。注意,集合中是不能有相同元素的,因此Python 在创建集合值的时候会自动删除掉重复的数据。

① 当然 Python 集合并不完全等同于数学中的集合,例如数学中的集合可能是无穷集。

>>> {1,2,3}
set([1, 2, 3])
>>> s = {1,1,2,2,2,3,3}
>>> s
set([1, 2, 3])
>>> set('set')
set(['s', 'e', 't'])
>>> set('sets')
set(['s', 'e', 't'])
>>> set([1,1,1,2,1])
set([1, 2])
>>> set((1,2,1,1,2,3,4))
set([1, 2, 3, 4])
>>> set()
set([])
>>> type(set())
<type 'set'>
>>> type({})
<type 'dict'>

集合类型支持多种运算,学过中学数学的读者很容易理解这些运算的含义。我们将常用 的集合运算列在表 6.6 中。

运算 含义
x in <集合> 检测 x 是否属于<集合>,返回 True 或 False
s1 | s2 并集
s1 & s2 交集
s1 – s2 差集
s1 ^ s2 对称差
s1 <= s2 检测 s1 是否 s2 的子集
s1 < s2 检测 s1 是否 s2 的真子集
s1 >= s2 检测 s1 是否 s2 的超集
s1 > s2 检测 s1 是否 s2 的真超集
s1 |= s2 将 s2 的元素并入 s1 中
len(s) s 中的元素个数

图 6.6 集合运算

下面是集合运算的例子:

>>> s1 = {1,2,3,4,5}
>>> s2 = {2,4,6,8}
>>> 6 in s1
False
>>> 6 in s2
True
>>> s1 | s2
set([1, 2, 3, 4, 5, 6, 8])
>>> s1 & s2
set([2, 4])
>>> s1 - s2
set([1, 3, 5])
>>> s1 |= s2
>>> s1
set([1, 2, 3, 4, 5, 6, 8])
>>> len(s2)
4

和序列一样,集合与 for 循环语句结合使用,可实现对集合中每个元素的遍历。例如, 接着上面的例子继续执行语句:

>>> for x in s2:
        print x,
8 2 4 6

Python 集合是可修改的数据类型,例如上面例子中修改了集合 s1 的值。但是,Python 集合中的元素必须是不可修改的!因此,集合的元素不能是列表、字典等,只能是数值、字 符串、元组之类。同样,集合的元素不能是集合,因为集合是可修改的。然而,Python 另 外提供了 frozenset()函数,可用来创建不可修改的集合,这种集合可以作为另一个集合的元 素。下面的语句展示了 set 和 frozenset 的区别:

>>> a = set(['hi','there'])
>>> b = set([a,3])
Traceback (most recent call last):
File "&lt;pyshell#74&gt;", line 1, in &lt;module&gt; b = set([a,3])
TypeError: unhashable type: 'set'
>>> a = frozenset(['hi','there'])
>>> b = set([a,3])
>>> b
set([3, frozenset(['there', 'hi'])])

Python 以面向对象方式实现集合类型,集合对象的方法如表 6.7 所示。

方法 含义
s1.union(s2) 即 s1 | s2
s1.intersection(s2) 即 s1 & s2
s1.difference(s2) 即 s1 – s2
s1.symmetric_difference(s2) 即 s1 ^ s2
s1.issubset(s2) 即 s1 <= s2
s1.issuperset(s2) 即 s1 >= s2
s1.update(s2) s1 |= s2
s.add(x) 向 s 中增加元素 x
s.remove(x) 从 s 中删除元素 x(无 x 则出错)
s.discard(x) 从 s 中删除元素 x(无 x 也不出错)
s.pop() 从 s 中删除并返回任一元素
s.clear() 从 s 中删除所有元素
s.copy() 复制 s

表 6.7 集合对象的方法

接着前面的例子,下面通过集合对象方法的调用来处理集合数据:

>>> s2.union([1,2,3])
set([1, 2, 3, 4, 6, 8])
>>> s2.intersection((1,2,3,4))
set([2, 4])
>>> set([2,4]).issubset(s2)
True
>>> s2.issuperset(set([2,4]))
True
>>> s2.add(10)
>>> s2
set([8, 2, 4, 10, 6])
>>> print s2.pop()
8
>>> s2
set([2, 4, 10, 6])