集合


在Python中,集合(Set)是無序、元素不重複的集合。在Python3中,要建立集合,可以使用{}包 括元素的實字方式來建立集合。例如:
>>> admins = {'Justin', 'caterpillar'}
>>> users = {'momor', 'hamini', 'Justin'}
>>> 'Justin' in admins
True
>>> admins & users
{'Justin'}
>>> admins | users
{'hamini', 'caterpillar', 'Justin', 'momor'}
>>> admins - users
{'caterpillar'}
>>> admins ^ users
{'hamini', 'caterpillar', 'momor'}
>>> admins > users
False
>>> admins < users
False
>>>


建立集合後,可以使用in來測試元素是否在集合中,使用&作交集運算,使用|作 聯集運算,使用-作差集運算,使用^作 排除相同元素(XOR)運算,使用>測試左集合是否為右集 合的父集,使用<測試左集合是否為右集合的子集。

在上例中,亦示範了集合的應用方式之一,利用集合依序測試,'Justin'是否為站長之一?同時是站長也是使用者的有誰?站長與使用者有哪些人?站 長中不是使用者的有誰?沒有同時具備站長與使用者身份的有誰?站長群是否為使用者群的父集?站長群是否為使用者群的子集?

如果你要建立空集合,不可以直接使用{}不 包括任何元素的實字寫法,因為{}不 包括任何元素的實字寫法表示一個空字典物件,如果你要建立空集合,必須使用set類 別建構。例如:
>>> type({})
<class 'dict'>
>>> type(set())
<class 'set'>
>>> family = set()
>>> family
set()
>>> family.add('Justin')
>>> family.add('Momor')
>>> family.add('Hamimi')
>>> family
{'Hamimi', 'Justin', 'Momor'}
>>>


如果你要從字串的字元或串列的元素建立集合物件,不是直接使用實字寫法,而要使用set來建構。例如:
>>> set('Justin')
{'i', 'J', 'n', 's', 'u', 't'}
>>> set([1, 2, 3, 4])
{1, 2, 3, 4}
>>> {'Justin'}
{'Justin'}
>>> {[1, 2, 3, 4]}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>>


{'Justin'}是 將整個字串放在集合中,而不是將其中每個字元取出,當作個別元素放在集合中。而{[1, 2, 3, 4]}則會出錯,Python的集合物件要求物件必須實作__hash__() 方法,且必須傳回整數值,串列的__hash__是NoneType,沒有傳回整數值,因而出錯。

先前看過幾個可運用在集合上的運算子,事實上這些操作也以方法的方式存在:
>>> dir(set())
['__and__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__
format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__in
it__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt
__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '
__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__st
r__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'differe
nce', 'difference_update', 'discard', 'intersection', 'intersection_update', 'is
disjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 's
ymmetric_difference_update', 'union', 'update']
>>>


使用方法時要記得,在Python2.6與Python3,集合中不可以unhashable物件(未實作__hash__()__eq__())。 例如:
>>> family = {'Justin'}
>>> family
{'Justin'}
>>> family.add({'Momor', 'Hamini'})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> family.update({'Momor', 'Hamini'})
>>> family
{'Hamini', 'Justin', 'Momor'}
>>>


如果使用add()方 法給定一個集合物件,由於集合物件是unhashable,不能加入目標集合中,而需要將元素一個一個取出,再加入目標集合中,這可以使用update()方 法來完成。也就是相當於:
>>> family = {'Justin'}
>>> for person in {'Momor', 'Hamini'}:
...     family.add(person)
...
>>> family
{'Hamini', 'Justin', 'Momor'}
>>>


上例中亦示範了,for迴 圈可以用在集合物件上,一個一個取出元素。

Python是強型別語言,在集合運算時,&、|等運算子左右運算元必須都是集合物件。如果右運算元不是集合物件,但想要將其中的元素取出作 集合運算的話,就可以借助方法。例如:
>>> admins = {'Justin', 'caterpillar'}
>>> users = ['momor', 'hamini', 'Justin']
>>> admins & users
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'set' and 'list'
>>> admins.intersection(users)
{'Justin'}
>>> admins | users

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'set' and 'list'
>>> admins.union(users)
{'hamini', 'caterpillar', 'Justin', 'momor'}
>>>