全部博文(471)
分类: Python/Ruby
2013-02-27 14:01:47
集合set 是装有独特值的无序“袋子”。一个简单的集合可以包含任何数据类型的值。如果有两个集合,则可以执行像联合、交集以及集合求差等标准集合运算。
重中之重。创建集合非常简单。
[] []
① | 要创建只包含一个值的集合,仅需将该值放置于花括号之间。({})。 |
② | 实际上,集合以 的形式实现,但目前还无须考虑这一点。 |
③ | 要创建多值集合,请将值用逗号分开,并用花括号将所有值包裹起来。 |
还可以 为基础创建集合。
[] []>>> a_list = ['a', 'b', 'mpilgrim', True, False, 42] >>> a_set = set(a_list) ① >>> a_set ② {'a', False, 'b', True, 'mpilgrim', 42} >>> a_list ③ ['a', 'b', 'mpilgrim', True, False, 42]
① | 要从列表创建集合,可使用 set() 函数。(懂得如何实现集合的学究可能指出这实际上并不是调用某个函数,而是对某个类进行实例化。我保证在本书稍后的地方将会学到其中的区别。目前而言,仅需知道 set() 行为与函数类似,以及它返回一个集合。) |
② | 正如我之前提到的,简单的集合可以包括任何数据类型的值。而且,如我之前所提到的,集合是 无序的。该集合并不记得用于创建它的列表中元素的最初顺序。如果向集合中添加元素,它也不会记得添加的顺序。 |
③ | 初始的列表并不会发生变化。 |
还没有任何值?没有问题。可以创建一个空的集合。
[] []>>> a_set = set() ① >>> a_set ② set() >>> type(a_set) ③'set'> >>> len(a_set) ④ 0 >>> not_sure = {} ⑤ >>> type(not_sure) 'dict'>
① | 要创建空集合,可不带参数调用 set() 。 |
② | 打印出来的空集合表现形式看起来有点儿怪。也许,您期望看到一个 {} 吧 ?该符号表示一个空的字典,而不是一个空的集合。本章稍后您将学到关于字典的内容。 |
③ | 尽管打印出的形式奇怪,这 确实是 一个集合…… |
④ | …… 同时该集合没有任何成员。 |
⑤ | 由于从 Python 2 沿袭而来历史的古怪规定,不能使用两个花括号来创建空集合。该操作实际创建一个空字典,而不是一个空集合。 |
有两种方法可向现有集合中添加值: add() 方法和 update() 方法。
[] []>>> a_set = {1, 2} >>> a_set.add(4) ① >>> a_set {1, 2, 4} >>> len(a_set) ② 3 >>> a_set.add(1) ③ >>> a_set {1, 2, 4} 3
① | add() 方法接受单个可以是任何数据类型的参数,并将该值添加到集合之中。 |
② | 该集合现在有三个成员了。 |
③ | 集合是装 唯一值 的袋子。如果试图添加一个集合中已有的值,将不会发生任何事情。将不会引发一个错误;只是一条空操作。 |
④ | 该集合 仍然 只有三个成员。 |
[] []>>> a_set = {1, 2, 3} >>> a_set {1, 2, 3} >>> a_set.update({2, 4, 6}) ① >>> a_set ② {1, 2, 3, 4, 6} >>> a_set.update({3, 6, 9}, {1, 2, 3, 5, 8, 13}) ③ >>> a_set {1, 2, 3, 4, 5, 6, 8, 9, 13} >>> a_set.update([10, 20, 30]) ④ >>> a_set {1, 2, 3, 4, 5, 6, 8, 9, 10, 13, 20, 30}
① | update() 方法仅接受一个集合作为参数,并将其所有成员添加到初始列表中。其行为方式就像是对参数集合中的每个成员调用 add() 方法。 |
② | 由于集合不能包含重复的值,因此重复的值将会被忽略。 |
③ | 实际上,可以带任何数量的参数调用 update() 方法。如果调用时传递了两个集合, update() 将会被每个集合中的每个成员添加到初始的集合当中(丢弃重复值)。 |
④ | update() 方法还可接受一些其它数据类型的对象作为参数,包括列表。如果调用时传入列表,update() 将会把列表中所有的元素添加到初始集合中。 |
有三种方法可以用来从集合中删除某个值。前两种,discard() 和 remove() 有细微的差异。
[] []>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} >>> a_set {1, 3, 36, 6, 10, 45, 15, 21, 28} >>> a_set.discard(10) ① >>> a_set {1, 3, 36, 6, 45, 15, 21, 28} >>> a_set.discard(10) ② >>> a_set {1, 3, 36, 6, 45, 15, 21, 28} >>> a_set.remove(21) ③ >>> a_set {1, 3, 36, 6, 45, 15, 28} >>> a_set.remove(21) ④ Traceback (most recent call last): File "", line 1, in KeyError: 21
① | discard() 接受一个单值作为参数,并从集合中删除该值。 |
② | 如果针对一个集合中不存在的值调用 discard() 方法,它不进行任何操作。不产生错误;只是一条空指令。 |
③ | remove() 方法也接受一个单值作为参数,也从集合中将其删除。 |
④ | 区别在这里:如果该值不在集合中,remove() 方法引发一个 KeyError 例外。 |
就像列表,集合也有个 pop() 方法。
[] []>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} >>> a_set.pop() ① 1 >>> a_set.pop() 3 >>> a_set.pop() 36 >>> a_set {6, 10, 45, 15, 21, 28} >>> a_set.clear() ② >>> a_set set() >>> a_set.pop() ③ Traceback (most recent call last): File "", line 1, in KeyError: 'pop from an empty set'
① | pop() 方法从集合中删除某个值,并返回该值。然而,由于集合是无序的,并没有“最后一个”值的概念,因此无法控制删除的是哪一个值。它基本上是随机的。 |
② | clear() 方法删除集合中 所有 的值,留下一个空集合。它等价于 a_set = set(),该语句创建一个新的空集合,并用之覆盖 a_set 变量的之前的值。 |
③ | 试图从空集合中弹出某值将会引发 KeyError 例外。 |
Python 的 集合 类型支持几种常见的运算。
[] []>>> a_set = {2, 4, 5, 9, 12, 21, 30, 51, 76, 127, 195} >>> 30 in a_set ① True >>> 31 in a_set False >>> b_set = {1, 2, 3, 5, 6, 8, 9, 12, 15, 17, 18, 21} >>> a_set.union(b_set) ② {1, 2, 195, 4, 5, 6, 8, 12, 76, 15, 17, 18, 3, 21, 30, 51, 9, 127} >>> a_set.intersection(b_set) ③ {9, 2, 12, 5, 21} >>> a_set.difference(b_set) ④ {195, 4, 76, 51, 30, 127} >>> a_set.symmetric_difference(b_set) ⑤ {1, 3, 4, 6, 8, 76, 15, 17, 18, 195, 127, 30, 51}
① | 要检测某值是否是集合的成员,可使用 in 运算符。其工作原理和列表的一样。 |
② | union() 方法返回一个新集合,其中装着 在两个 集合中出现的元素。 |
③ | intersection() 方法返回一个新集合,其中装着 同时 在两个集合中出现的所有元素。 |
④ | difference() 方法返回的新集合中,装着所有在 a_set 出现但未在 b_set 中的元素。 |
⑤ | symmetric_difference() 方法返回一个新集合,其中装着所有 只在其中一个 集合中出现的元素。 |
这三种方法是对称的。
[] []# continued from the previous example >>> b_set.symmetric_difference(a_set) ① {3, 1, 195, 4, 6, 8, 76, 15, 17, 18, 51, 30, 127} >>> b_set.symmetric_difference(a_set) == a_set.symmetric_difference(b_set) ② True >>> b_set.union(a_set) == a_set.union(b_set) ③ True >>> b_set.intersection(a_set) == a_set.intersection(b_set) ④ True >>> b_set.difference(a_set) == a_set.difference(b_set) ⑤ False
① | a_set 与 b_set 的对称差分 看起来 和b_set 与 a_set 的对称差分不同,但请记住:集合是无序的。任何两个包含所有同样值(无一遗漏)的集合可认为是相等的。 |
② | 而这正是这里发生的事情。不要被 Python Shell 对这些集合的输出形式所愚弄了。它们包含相同的值,因此是相等的。 |
③ | 对两个集合的 Union[并集]操作也是对称的。 |
④ | 对两个集合的 Intersection[交集]操作也是对称的。 |
⑤ | 对两个集合的 Difference[求差]操作不是对称的。这是有意义的;它类似于从一个数中减去另一个数。操作数的顺序会导致结果不同。 |
最后,有几个您可能会问到的问题。
[] []>>> a_set = {1, 2, 3} >>> b_set = {1, 2, 3, 4} >>> a_set.issubset(b_set) ① True >>> b_set.issuperset(a_set) ② True >>> a_set.add(5) ③ >>> a_set.issubset(b_set) False >>> b_set.issuperset(a_set) False
① | a_set 是 b_set 的 子集 — 所有 a_set 的成员均为 b_set 的成员。 |
② | 同样的问题反过来说, b_set 是 a_set 的 超集,因为 a_set 的所有成员均为 b_set 的成员。 |
③ | 一旦向 a_set 添加一个未在 b_set 中出现的值,两项测试均返回 False 。 |
可在 if 这样的 使用集合。
[] []>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(set()) ① no, it's false >>> is_it_true({'a'}) ② yes, it's true >>> is_it_true({False}) ③ yes, it's true
① | 在布尔类型上下文环境中,空集合为假值。 |
② | 任何至少包含一个上元素的集合为真值。 |
③ | 任何至少包含一个上元素的集合为真值。元素的值无关紧要。 |