Python集合(set),是一個很有意思的資料結構。從形式上看,它像字典有key但沒有value,它的寫法是這樣的s = {'a', 'b', 'c'}
,是不是像一個沒有value的字典?另一方面,它又像是一個用花括號替換了方括號的列表,但它不能像列表那樣用索引訪問元素。
其實,Python集合在內部實現上就是一個沒有value的字典,所以它跟字典很像。既然和字典很像,那麼還要集合幹什麼?集合主要用來幹什麼呢?
集合主要用於測試一個物件是不是在一堆物件集裡面,也就是in
運算。這個功能其實列表也可以,比如1 in [2,3,4,5]
,但是用列表的速度遠遠低於集合,尤其是在這一堆物件的數量非常大時。
列表因為是順序儲存的,它的查詢時間複雜度是O(n)
,而集合是用hash table實現的,其時間複雜度是O(1)
。
Python集合(set)的建立
集合可以通過set()
來建立一個空集合,也可以把一個列表轉換為集合。類似字典那樣在花括號內可以放用逗號,
隔開的多個物件:
In [1]: s = set()
In [2]: type(s)
Out[2]: set
In [3]: set([1,2,3,4,5])
Out[3]: {1, 2, 3, 4, 5}
In [4]: set([1,2,3,3,5])
Out[4]: {1, 2, 3, 5}
In [5]: s = {'a', 'd', 'e', 'c', 'b'}
In [6]: s2 = {1, 'a', True}
In [7]: s = {'a', 'a', 'a'}
In [8]: s
Out[8]: {'a'} # 字典裡面的元素不能重複
跟字典的鍵不能是可變物件一樣,集合裡面也不能是列表、集合、字典:
In [9]: s = {'a', [1,2]}
------------------------
TypeError Traceback (most recent call last)
<ipython-input-9-0a9fe58d273d> in <module>
----> 1 s = {'a', [1,2]}
TypeError: unhashable type: 'list'
In [10]: s = {'a', {'a':1}}
---------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-f0b724762652> in <module>
----> 1 s = {'a', {'a':1}}
TypeError: unhashable type: 'dict'
Python集合(set)的訪問
集合不能像列表那樣通過索引訪問內部某一個元素,只能通過遍歷訪問全部元素,或通過變數名訪問整個集合:
In [13]: s = {'a', 'b', 'c'}
In [14]: s
Out[14]: {'a', 'b', 'c'}
In [15]: for x in s:
...: print(x)
...:
a
c
b
集合相關的內建函式
Python內建了一些函式可以用於操作集合,它們是:
- len()
返回集合的長度,即集合包含的元素的個數。空集合的長度是0
In [41]: len({'a', 'b'})
Out[41]: 2
In [42]: len(set())
Out[42]: 0
- any()和all()
類似於對列表、tuple的操作。
any(): 只要集合有一個元素為True則返回True;
all(): 只有集合的所有元素都為True才返回True;
In [45]: any({'', 0, False})
Out[45]: False
In [46]: all({'', 0, False})
Out[46]: False
In [47]: all({'a', 0:, False})
Out[47]: False
In [48]: any({'a', 0:, False})
Out[48]: True
In [49]: any(set())
Out[49]: False
In [50]: all(set())
Out[50]: True
跟空字典一樣,它卻認為是所有元素都為True,all(set())
返回True。
- sorted()
跟操作列表、tuple的效果一樣,它把集合的所有元素進行排序
In [51]: sorted({'a', 'c', 'b'})
Out[51]: ['a', 'b', 'c']
in 運算子
跟列表,元組一樣,in
用來檢驗一個物件是不是在集合中:
In [56]: 'a' in {'a', 'c', 'b'}
Out[56]: True
In [57]: '3' in {'a', 'c', 'b'}
Out[57]: False
In [58]: '3' not in {'a', 'c', 'b'}
Out[58]: True
遍歷集合:
In [59]: for k in {'a', 'c', 'b'}:
...: print(key)
...:
a
c
b
集合的內建方法:
(1)add(x)
把物件x新增到集合中。
In [25]: s = {'a', 'b', 'c'}
In [26]: s.add(1)
In [27]: s
Out[27]: {1, 'a', 'b', 'c'}
(2)update()
把多個物件新增到集合中。
In [28]: s.update([1,2,3])
In [29]: s
Out[29]: {1, 2, 3, 'a', 'b', 'c'}
In [30]: s.update(['x', 'y'], {7,8,0})
In [31]: s
Out[31]: {0, 1, 2, 3, 7, 8, 'a', 'b', 'c', 'x', 'y'}
(3)discard(x) 和 remove(x)
這兩個都是從集合中刪除一個元素x。不同的是,如果x不在集合中,discard()會忽略;而remove()會丟擲KeyError
的錯誤:
In [32]: s
Out[32]: {0, 1, 2, 3, 7, 8, 'a', 'b', 'c', 'x', 'y'}
In [33]: s.discard(0)
In [34]: s.remove(1)
In [35]: s
Out[35]: {2, 3, 7, 8, 'a', 'b', 'c', 'x', 'y'}
In [36]: s.discard('z')
In [37]: s.remove('z')
----------------------
KeyError Traceback (most recent call last)
<ipython-input-37-a9e7a977e50c> in <module>
----> 1 s.remove('z')
KeyError: 'z'
(4)pop()
類似字典的pop()和列表的pop(),都是從其中刪除一個元素並返回該元素。因為集合沒有key和索引的概念,所以集合的pop()不帶引數。
(5)clear()
清空一個集合
In [40]: s
Out[40]: {2, 3, 7, 8, 'a', 'b', 'c', 'x', 'y'}
In [41]: s.clear()
In [42]: s
Out[42]: set()
(6)copy()
跟字典的copy()一樣,返回一個集合的深拷貝。
In [44]: s = {'a', 'b', 'c'}
In [45]: s2 = s.copy()
In [46]: s2
Out[46]: {'a', 'b', 'c'}
In [47]: s.add(1)
In [48]: s
Out[48]: {1, 'a', 'b', 'c'}
In [49]: s2
Out[49]: {'a', 'b', 'c'}
(7)union()
求兩個或多個集合的並集,即把這些集合的所有元素放在一起組成新的集合並返回。它不改變原來的集合。
In [51]: s1, s2, s3 = {1,2,3}, {4,5,6}, {6,7,8}
In [52]: s1.union(s2)
Out[52]: {1, 2, 3, 4, 5, 6}
In [53]: s1
Out[53]: {1, 2, 3}
In [54]: s1.union(s2, s3)
Out[54]: {1, 2, 3, 4, 5, 6, 7, 8}
(8)intersection()
求兩個或多個集合的交集,即把這些集合中共同含有的元素放在一起組合成新的集合並返回。同樣它也不改變原來的集合。
In [55]: s1.intersection(s2)
Out[55]: set()
In [56]: s2.intersection(s3)
Out[56]: {6}
In [57]: s1.intersection(s2, s3)
Out[57]: set()
(10)difference()
求一個集合S與另一個或多個集合的差集,即把只包含在集合S卻不在做比較的集合中的元素組成新的集合並返回,同樣它也不改變原來的集合。相當於集合的減法。
In [58]: s1.difference(s2)
Out[58]: {1, 2, 3} # 返回s1包含卻不在s2中的元素組成的集合: s1 - s2
In [59]: s2.difference(s1)
Out[59]: {4, 5, 6} # s2包含,s1不包含: s2 - s1
In [60]: s2.difference(s3)
Out[60]: {4, 5} # s2包含,s3不包含: s2 - s3
In [61]: s2.difference(s3, s1)
Out[61]: {4, 5} # s2包含,s3,s1都不包含: s2 - s3 - s1
(11)symmetric_difference()
求兩個集合中除去交集之外的元素集合,即把不同時包含在兩個集合中的元素放在一起組成新的集合並返回。
In [63]: s1, s2, s3
Out[63]: ({1, 2, 3}, {4, 5, 6}, {6, 7, 8})
In [64]: s1.symmetric_difference(s2)
Out[64]: {1, 2, 3, 4, 5, 6}
In [65]: s2.symmetric_difference(s3)
Out[65]: {4, 5, 7, 8}
(12) intersection_update()
同intersection()一樣求得新集合,但是本方法改變呼叫它的物件。
In [74]: s1, s2, s3 = {1,2,3}, {4,5,6}, {6,7,8}
In [75]: s1.intersection(s2)
Out[75]: set()
In [76]: s1
Out[76]: {1, 2, 3}
In [77]: s1.intersection_update(s2)
In [78]: s1
Out[78]: set()
(13)difference_update()
同difference()一樣求得新集合,並用新集合改變呼叫該方法的集合。
In [79]: s1, s2, s3 = {1,2,3}, {4,5,6}, {6,7,8}
In [80]: s1.difference_update(s2)
In [81]: s1
Out[81]: {1, 2, 3}
(14)symmetric_difference_update()
通symmetric_difference()一樣求得新集合,並用新集合改變呼叫該方法的集合。
In [83]: s1, s2 = {1,2,3}, {4,5,6}
In [84]: s1.symmetric_difference_update(s2)
In [85]: s1
Out[85]: {1, 2, 3, 4, 5, 6}
(15)isdisjoint()
如果兩個集合沒有交集則返回True。
In [87]: s1, s2 = {1,2,3}, {4,5,6}
In [88]: s1.isdisjoint(s2)
Out[88]: True
(16)issubset()
判斷一個集合是不是另一個集合的子集,即它的所有元素都包含在另外一個集合中。
In [89]: {1,2}.issubset({1,2,3})
Out[89]: True
In [90]: {1,2}.issubset({1,2})
Out[90]: True
In [91]: {1,2}.issubset({1,5,6})
Out[91]: False
(17)issuperset()
判斷一個集合是不是另一個集合的超集,即它包含另外一個集合的所有元素。
In [93]: {1,2}.issuperset({1,2})
Out[93]: True
In [94]: {1,2}.issuperset({1,2,3})
Out[94]: False
In [95]: {1,2}.issuperset({1})
Out[95]: True
frozenset
顧名思義,就是凍住了的集合,即不可改變的集合。集合不能作為字典的key,但是frozenset卻可以。
In [100]: fs1 = frozenset()
In [101]: fs1
Out[101]: frozenset()
In [102]: fs2 = frozenset([1,2,3])
In [103]: fs2
Out[103]: frozenset({1, 2, 3})
In [104]: {fs2:3}
Out[104]: {frozenset({1, 2, 3}): 3}
總結
集合是沒有了value的字典,但它也有自己的個性。
練習
- 熟悉對集合的各種操作。
- 想一想集合可以和日常生活中哪些場景聯絡起來。
我的公眾號:猿人學 Python 上會分享更多心得體會,敬請關注。
***版權申明:若沒有特殊說明,文章皆是猿人學 yuanrenxue.com 原創,沒有猿人學授權,請勿以任何形式轉載。***