其他的数字类型——Sets——为什么是sets?

未匹配的标注

Set操作有许多常见用处,一些比数学上的用处更实用。比如,因为项在set中只保存一次,因此set可以被用来从其他集合中过滤重复值,然而在这个过程中项可能会被重新排序,因为set通常是无序的。简单地将集合转为set,然后再将它转换回来(这里set在list函数调用中可用是因为它们是可迭代的,这是另一个将在稍后讨论的技术细节):

>>> L = [1, 2, 1, 3, 2, 4, 5]
>>> set(L)
{1, 2, 3, 4, 5}
>>> L = list(set(L)) # 去重
>>> L
[1, 2, 3, 4, 5]
>>> list(set(['yy', 'cc', 'aa', 'xx', 'dd', 'aa'])) # 但顺序可能改变
['cc', 'xx', 'yy', 'dd', 'aa']

Set 还能被用来找出列表,字符串和其他可迭代对象的差异——简单地转换为set然后得到差集——然而(再一次)set的无序特性意味着结果可能和原来的不匹配。下面最后两个例子比较了在3.X中字符串对象类型的属性列表(在2.7中的结果是不同的):

>>> set([1, 3, 5, 7]) - set([1, 2, 4, 5, 6]) # 找出列表差异
{3, 7}
>>> set('abcdefg') - set('abdghij') # 找出字符串差异
{'c', 'e', 'f'}
>>> set('spam') - set(['h', 'a', 'm']) # 找出混合类型的差异
{'p', 's'}
>>> set(dir(bytes)) - set(dir(bytearray)) # 在bytes类型但不在bytearray类型中
{'__getnewargs__'}
>>> set(dir(bytearray)) - set(dir(bytes))
{'append', 'copy', '__alloc__', '__imul__', 'remove', 'pop', 'insert',
...更多...]

还可以使用set来执行顺序无关的相等测试(在测试前转为set),因为顺序在set中不重要。更规范地说,当且仅当每个set中的每个元素都包含在另一个set中,那么两个set才是相等的——也就是说,每个set是另一个的子集,不管顺序。比如,可以这样来比较本应该一样但以不同顺序产生的不同程序输出。对相等测试,测试前排序会得到相同的效果,但set不依赖于昂贵的排序操作,且该操作对它们的结果进行排序来支持额外的set不支持的数值测试(大于,小于等等):

>>> L1, L2 = [1, 3, 5, 2, 4], [2, 5, 3, 4, 1]
>>> L1 == L2 # 序列中顺序很重要
False
>>> set(L1) == set(L2) # 排序无关的相等
True
>>> sorted(L1) == sorted(L2) # 相似,但将结果排序
True
>>> 'spam' == 'asmp', set('spam') == set('asmp'), sorted('spam') ==
sorted('asmp')
(False, True, True)

Set还可以在遍历图表或其他循环结构时用来跟踪已到达的位置。比如,在第25章第31章中将分别学习的传递模块重载器和继承树列表的例子(必须跟踪已访问的项来避免循环),如在第19章的摘要中所讨论的。在这个上下文中使用列表是低效的,因为搜索需要线性扫描。虽然记录已访问的状态作为字典的键是高效的,但set提供了本质上等价的可选方案(而且可能更或更不直观,这取决于你问谁)。

最后,当处理大数据集时(比如,数据库查询结果)set 也很方便——两个set的交集包含两个类别都有的对象,并集则包含在每个set中的所有项。下面是一个有些现实意义的set操作实例,应用在一个假想公司中的人名列表,使用3.X/2.7的set字面量和3.X结果显示(在2.6和之前版本中使用set函数):

>>> engineers = {'bob', 'sue', 'ann', 'vic'}
>>> managers = {'tom', 'sue'}
>>> 'bob' in engineers # bob是工程师吗?
True
>>> engineers & managers # 谁既是工程师又是经理?
{'sue'}
>>> engineers | managers # 在每个类别中的所有人
{'bob', 'tom', 'sue', 'vic', 'ann'}
>>> engineers - managers # 不是经理的工程师
{'vic', 'ann', 'bob'}
>>> managers - engineers # 不是工程师的经理
{'tom'}
>>> engineers > managers # 所有的经理都是工程师吗? (超集)
False
>>> {'bob', 'sue'} < engineers # 他们两个都是工程师吗? (子集)
True
>>> (managers | engineers) > managers # 所有人是经理的超集
True
>>> managers  engineers # 谁在其中一个类别但不在两个?
{'tom', 'vic', 'ann', 'bob'}
>>> (managers | engineers) - (managers  engineers) # 交集!
{'sue'}

在Python库手册和一些数学和关系式数据库理论的书籍中,可以找到set操作的更多细节。而且,在第8章,Python 3.X的字典视图对象的上下文中,会对这里已经见过的一些set操作进行重新介绍,请保持关注。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~