第三章(提炼)字典和集合(三)

一. 集合论

集合的本质是许多唯一对象的聚集,因此,集合可以用于去重:

集合中的元素必须是可散列的,set 类型本身是不可散列的,但是 frozenset 可以。除了保证唯一性,集合还实现了很多基础的中缀运算符。给定两个集合 a 和 ba | b 返回的是它们的合集,a & b 得到的是交集,而 a - b 得到的是差集。

演示1  needles 的元素在 haystack 里出现的次数,两个变量都是 set 类型

演示2  needles 的元素在 haystack 里出现的次数,这次的代码可以用在任何可迭代对象上

以上的所有例子的运行时间都能在 3 毫秒左右,在含有 10 000 000 个元素的 haystack 里搜索 1000 个值,算下来大概是每个元素 3 微秒。除了速度极快的查找功能(这也得归功于它背后的散列表),内置的 set 和 frozenset 提供了丰富的功能和操作,不但让创建集合的方式丰富多彩,而且对于 set 来讲,我们还可以对集合里已有的元素进行修改。

1.1 集合字面量

除空集之外,集合的字面量——{1}{1, 2},等等——看起来跟它的数学形式一模一样。如果是空集,那么必须写成 set() 的形式,如果只是写成 {} 的形式,跟以前一样,你创建的其实是个空字典。

像 {1, 2, 3} 这种字面量句法相比于构造方法(set([1, 2, 3]))要更快且更易读。用 dis.dis(反汇编函数)来看看两个方法的字节码的不同:

特殊的字节码 BUILD_SET 几乎完成了所有的工作。而使用set()创建时,3 种不同的操作代替了上面的 BUILD_SET:LOAD_NAMEBUILD_LIST CALL_FUNCTION。 

由于 Python 里没有针对 frozenset 的特殊字面量句法,我们只能采用构造方法:

1.2 集合推导

演示2  新建一个 Latin-1 字符集合,该集合里的每个字符的 Unicode 名字里都有“SIGN”这个单词

unicodedata 模块里导入 name 函数,用以获取字符的名字。把编码在 32~255 之间的字符的名字里有“SIGN”单词的挑出来,放到一个集合里。

1.3 集合的操作

列出了可变和不可变集合所拥有的方法的概况,其中不少是运算符重载的特殊方法。

中缀运算符需要两侧的被操作对象都是集合类型,但是其他的所有方法则只要求所传入的参数是可迭代对象。例如,想求 4 个聚合类型 abc d 的合集,可以用 a.union(b, c, d),这里 a 必须是个 set,但是 bc d 则可以是任何类型的可迭代对象。

表 1-1:集合的数学运算:这些方法或者会生成新集合,或者会在条件允许的情况下就地修改集合

数学符号 Python运算符 方法 描述
S ∩ Z s & z s.__add__(z)
s z 的交集
z & s s.__radd__(z)
反向 & 操作
s.intersection(it, ...)
把可迭代的 it 和其他所有参数转化为集合,然后求它们与 s 的交集
s &= z
s.__iand__(z)
s 更新为 s z 的交集
s.intersection_update(it, ...)
把可迭代的 it 和其他所有参数转化为集合,然后求得它们与 s 的交集,然后把 s 更新成这个交集
S ∪ Z
s | z
s.__or__(z)
s z 的并集
z | s
s.__ror__(z)
| 的反向操作
s.union(it, ...)
把可迭代的 it 和其他所有参数转化为集合,然后求它们和 s 的并集
s |= z
s.__ior__(z)
s 更新为 s z 的并集
s.update(it, ...)
把可迭代的 it 和其他所有参数转化为集合,然后求它们和 s 的并集,并把 s 更新成这个并集
S \ Z
s - z s.__sub__(z)
s z 的差集,或者叫作相对补集
z - s s.__rsub__(z)
- 的反向操作
s.difference(it, ...)
把可迭代的 it 和其他所有参数转化为集合,然后求它们和 s 的差集
s -= z s.__isub__(z)
s 更新为它与 z 的差集
s.difference_update(it, ...)
把可迭代的 it 和其他所有参数转化为集合,求它们和 s 的差集,然后把 s 更新成这个差集
s.symmetric_difference(it)
s set(it) 的对称差集
S △ Z
s ^ z
s.__xor__(z)
s z 的对称差集
z ^ s
s.__rxor__(z)
^ 的反向操作
s.symmetric_difference_update(it, ...)
把可迭代的 it 和其他所有参数转化为集合,然后求它们和 s 的对称差集,最后把 s 更新成该结果
s ^= z
s.__ixor__(z)
s 更新成它与 z 的对称差集

表 1-2:集合的比较运算符,返回值是布尔类型

数学符号 Python运算符 方法 描述
—— —— s.isdisjoint(z)
查看 s z 是否不相交(没有共同元素)
e S
e in s s.__contains__(e)
元素 e 是否属于 s
S Z
s <= z s.__le__(z)
s 是否为 z 的子集
s.issubset(it)
把可迭代的 it 转化为集合,然后查看 s 是否为它的子集
S Z
s < z s.__lt__(z)
s 是否为 z 的真子集
S Z
s >= z s.__ge__(z)
s 是否为 z 的父集
s.issuperset(it)
把可迭代的 it 转化为集合,然后查看 s 是否为它的父集
S Z
s > z s.__gt__(z)
s 是否为 z 的真父集

 表 1-3:集合类型的其他方法

方法 set frozenset 描述
s.add(e) ×
把元素 e 添加到 s
s.clear()
×
移除掉 s 中的所有元素
s.copy()
s 浅复制
s.discard(e)
×
如果 s 里有 e 这个元素的话,把它移除
s.__iter__()
返回 s 的迭代器
s.__len__()
len(s)
s.pop()
×
s 中移除一个元素并返回它的值,若 s 为空,则抛出 KeyError 异常
s.remove(e)
×
s 中移除 e 元素,若 e 元素不存在,则抛出 KeyError 异常

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章