在上一期詳解tuple元組的用法後,來總結Python裏面最後一種常見的數據類型:集合(Set)python
與dict相似,set也是一組key的集合,但不存儲value。因爲key不能重複,因此,在set中,沒有重複的key。建立一個set,須要提供一個list做爲輸入集集合,重複元素在set中會被自動被過濾,經過add(key)方法往set中添加元素,重複添加不會有效果。shell
總而言之,Set具備三個顯著特色:bash
咱們有兩種方式能夠建立一個Set,可使用內置的set()方法,或是使用中括號{} 建立模板以下:函數
x = set(<iter>)
x = {<obj>, <obj>, ..., <obj>}
複製代碼
如今讓咱們來看例子~測試
set()內置方法建立ui
x = set(['foo', 'bar', 'baz', 'foo', 'qux']) # 傳入List
print(x)
y = set(('foo', 'bar', 'baz', 'foo', 'qux')) #傳入元組
print(y)
Out: {'qux', 'foo', 'bar', 'baz'} # 注意到無序了吧~
{'bar', 'qux', 'baz', 'foo'}
複製代碼
這裏要注意用set()內置方法建立時必定要傳遞一個能夠迭代的參數,還有從輸出結果相信你們已經發現set的第一個特色了:無序spa
字符串也是可迭代的,所以字符串也能夠傳遞給set()3d
s = 'quux'
a = set(s)
print(a)
Out: {'u', 'q', 'x'} # 無序,惟一
複製代碼
這裏又體現了set的第二個特色:元素惟一性code
{} 方法建立cdn
>>> x = {'foo', 'bar', 'baz', 'foo', 'qux'}
>>> x
{'qux', 'foo', 'bar', 'baz'}
複製代碼
這裏考慮到以後例子太多,實在不能每次都打print啦,這種形式你們看的更清楚,這個直接用{}建立很簡單,只要傳遞進元素就行啦
建立空集合
Set能夠是空的。可是,請記住Python將空花括號 {} 視爲空字典,所以定義空集的惟一方法是使用set()函數
>>> x = set()
>>> type(x)
<class 'set'>
>>> x = {}
>>> type(x)
<class 'dict'>
複製代碼
一個空集合用布爾類型顯示爲False
>>> x = set()
>>> bool(x)
False
>>> x or 1
1
>>> x and 1
set()
複製代碼
對比小結
對於這兩種方法建立Set,本質區別在於如下兩點
補充說明
集合中的元素能夠是不一樣類型的對象,不必定非要是同一類型的,能夠包含不一樣類型,好比:
>>> x = {42, 'foo', 3.14159, None}
>>> x
{None, 'foo', 42, 3.14159}
複製代碼
但同時不要忘記set元素必須是不可變的。例如,元組能夠包括在集合中:
>>> x = {42, 'foo', (1, 2, 3), 3.14159}
>>> x
{42, 'foo', 3.14159, (1, 2, 3)}
複製代碼
但列表和字典是可變的,所以它們不能成爲Set的元素:
>>> a = [1, 2, 3]
>>> {a}
Traceback (most recent call last):
File "<pyshell#70>", line 1, in <module>
{a}
TypeError: unhashable type: 'list'
>>> d = {'a': 1, 'b': 2}
>>> {d}
Traceback (most recent call last):
File "<pyshell#72>", line 1, in <module>
{d}
TypeError: unhashable type: 'dict'
複製代碼
len()函數返回集合中元素的數量,而in和not in運算符可用於測試是否爲Set中的元素:
>>> x = {'foo', 'bar', 'baz'}
>>> len(x)
3
>>> 'bar' in x
True
>>> 'qux' in x
False
複製代碼
方法和運算符
許多可用於Python其餘數據類型的操做對集合沒有意義。例如,沒法對集合創建索引或切片。可是,Python在set對象上提供了運算符,這些操做符其實不少和數學裏是如出一轍的,相信數學好的朋友們對這部分簡直不要太熟悉
因此對於Set的操做除了用普通的內置方法,咱們也可使用運算符,比較方便
Union 並集
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'baz', 'qux', 'quux'}
複製代碼
如今咱們想求x1,x2的並集,以下圖所示:
具體實現方法以下,或是用方法,或是用操做符:
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'baz', 'qux', 'quux'}
>>> x1.union(x2)
{'foo', 'qux', 'quux', 'baz', 'bar'}
>>> x1 | x2
{'foo', 'qux', 'quux', 'baz', 'bar'}
複製代碼
若是有兩個以上的Set也是沒有問題的,原理都是同樣的:
>>> a = {1, 2, 3, 4}
>>> b = {2, 3, 4, 5}
>>> c = {3, 4, 5, 6}
>>> d = {4, 5, 6, 7}
>>> a.union(b, c, d)
{1, 2, 3, 4, 5, 6, 7}
>>> a | b | c | d
{1, 2, 3, 4, 5, 6, 7}
複製代碼
Intersection 交集
如今還讓咱們用剛纔建立好的兩個set,所求交集以下圖:
實現仍然是兩種方法:>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'baz', 'qux', 'quux'}
>>> x1.intersection(x2)
{'baz'}
>>> x1 & x2
{'baz'}
複製代碼
若是有多個集合的狀況上面的方法依然有效,可是注意,結果僅包含全部指定集合中都存在的元素。
>>> a = {1, 2, 3, 4}
>>> b = {2, 3, 4, 5}
>>> c = {3, 4, 5, 6}
>>> d = {4, 5, 6, 7}
>>> a.intersection(b, c, d)
{4}
>>> a & b & c & d
{4}
複製代碼
Difference 差集
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'baz', 'qux', 'quux'}
>>> x1.difference(x2)
{'foo', 'bar'}
>>> x1 - x2
{'foo', 'bar'}
複製代碼
仍是老樣子,適用於2個及以上的集合:
>>> a = {1, 2, 3, 30, 300}
>>> b = {10, 20, 30, 40}
>>> c = {100, 200, 300, 400}
>>> a.difference(b, c)
{1, 2, 3}
>>> a - b - c
{1, 2, 3}
複製代碼
指定多個集合時,操做從左到右執行。在上面的示例中,首先計算a - b,獲得{1,2,3,300}。而後從該集合中減去c,留下{1,2,3},具體流程以下圖所示:
Symmetric Difference 對稱差集
實現方法以下;
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'baz', 'qux', 'quux'}
>>> x1.symmetric_difference(x2)
{'foo', 'qux', 'quux', 'bar'}
>>> x1 ^ x2
{'foo', 'qux', 'quux', 'bar'}
複製代碼
老規矩,支持2個及以上set的連續操做:
>>> a = {1, 2, 3, 4, 5}
>>> b = {10, 2, 3, 4, 50}
>>> c = {1, 50, 100}
>>> a ^ b ^ c
{100, 5, 10}
複製代碼
當指定多個集合時,操做從左到右執行,奇怪的是,雖然 ^ 運算符容許多個集合,但.symmetric_difference()方法不容許
>>> a = {1, 2, 3, 4, 5}
>>> b = {10, 2, 3, 4, 50}
>>> c = {1, 50, 100}
>>> a.symmetric_difference(b, c)
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
a.symmetric_difference(b, c)
TypeError: symmetric_difference() takes exactly one argument (2 given)
複製代碼
x1.isdisjoint(x2) 判斷是否相交
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'baz', 'qux', 'quux'}
>>> x1.isdisjoint(x2)
False
>>> x2 - {'baz'}
{'quux', 'qux'}
>>> x1.isdisjoint(x2 - {'baz'})
True
複製代碼
從這個栗子能夠看出,若是兩個Set沒有共同元素返回True,若是有返回True,若是返回True同時也意味着他們之間的交集爲空集,這個很好理解:
>>> x1 = {1, 3, 5}
>>> x2 = {2, 4, 6}
>>> x1.isdisjoint(x2)
True
>>> x1 & x2
set()
複製代碼
注意:目前尚未運算符對應這個方法
x1.issubset(x2) 判斷x1是否爲x2子集
>>> x1 = {'foo', 'bar', 'baz'}
>>> x1.issubset({'foo', 'bar', 'baz', 'qux', 'quux'})
True
>>> x2 = {'baz', 'qux', 'quux'}
>>> x1 <= x2
False
複製代碼
一個集合自己固然是它本身的子集啦:
>>> x = {1, 2, 3, 4, 5}
>>> x.issubset(x)
True
>>> x <= x
True
複製代碼
x1<x2 判斷x1是否爲x2的真子集
首先。。。讓咱們回顧一下數學知識:真子集與子集相似,除了集合不能相同。若是x1的每一個元素都在x2中,而且x1和x2不相等,則集合x1被認爲是另外一個集合x2的真子集
換個高大上的說法也能夠:若是集合A⊆B,存在元素x∈B,且元素x不屬於集合A,咱們稱集合A與集合B有真包含關係,集合A是集合B的真子集(proper subset)。記做A⊊B(或B⊋A),讀做「A真包含於B」(或「B真包含A」)
>>> x1 = {'foo', 'bar'}
>>> x2 = {'foo', 'bar', 'baz'}
>>> x1 < x2
True
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'foo', 'bar', 'baz'}
>>> x1 < x2
False
複製代碼
雖然Set被認爲是其自身的子集,但它自己並非本身的真子集:
>>> x = {1, 2, 3, 4, 5}
>>> x <= x
True
>>> x < x
False
複製代碼
注意:目前尚未方法對應這個運算符
x1.issuperset(x2) 判斷x1是否爲x2的超集
>>> x1 = {'foo', 'bar', 'baz'}
>>> x1.issuperset({'foo', 'bar'})
True
>>> x2 = {'baz', 'qux', 'quux'}
>>> x1 >= x2
False
複製代碼
咱們剛纔已經看到過了一個Set是它本身自己的子集,這裏也是同樣的,它同時也是本身的超集
>>> x = {1, 2, 3, 4, 5}
>>> x.issuperset(x)
True
>>> x >= x
True
複製代碼
x1 > x2 判斷x1是否爲x2的真超集
真超集與超集相同,除了集合不能相同。若是x1包含x2的每一個元素,而且x1和x2不相等,則集合x1被認爲是另外一個集合x2的真超集。
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'foo', 'bar'}
>>> x1 > x2
True
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'foo', 'bar', 'baz'}
>>> x1 > x2
False
複製代碼
一個集合不是它本身的真超集,和真子集的原理相同
>>> x = {1, 2, 3, 4, 5}
>>> x > x
False
複製代碼
雖然集合中包含的元素必須是不可變類型,但能夠修改集合自己。與上面的操做相似,可使用多種運算符和方法來更改集合的內容。
**x1.update(x2) 經過union修改集合元素 **
x1.update(x2) 和 x1 |= x2 做用是向集合x1中添加x2中全部x1不存在的元素。 停下3秒,我仔細讀了這句話,以爲我表達的還能夠,不知道你們讀上去繞不繞,先看例子:
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'foo', 'baz', 'qux'}
>>> x1 |= x2
>>> x1
{'qux', 'foo', 'bar', 'baz'}
>>> x1.update(['corge', 'garply'])
>>> x1
{'qux', 'corge', 'garply', 'foo', 'bar', 'baz'}
複製代碼
**x1.intersection(x2) 經過intersection修改集合元素 **
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'foo', 'baz', 'qux'}
>>> x1 &= x2
>>> x1
{'foo', 'baz'}
>>> x1.intersection_update(['baz', 'qux'])
>>> x1
{'baz'}
複製代碼
**x1.difference_update(x2) 經過difference修改集合元素 **
x1.difference_update(x2) and x1 -= x2 會讓集合x1移除全部在x2出現的屬於x1的元素:
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'foo', 'baz', 'qux'}
>>> x1 -= x2
>>> x1
{'bar'}
>>> x1.difference_update(['foo', 'bar', 'qux'])
>>> x1
set()
複製代碼
**x1.symmetric_difference_update(x2) 經過對稱差集修改集合元素 **
>>> x1 = {'foo', 'bar', 'baz'}
>>> x2 = {'foo', 'baz', 'qux'}
>>>
>>> x1 ^= x2
>>> x1
{'bar', 'qux'}
>>>
>>> x1.symmetric_difference_update(['qux', 'corge'])
>>> x1
{'bar', 'corge'}
複製代碼
x.add( 添加元素
這個就很簡單了, 相似List:
>>> x = {'foo', 'bar', 'baz'}
>>> x.add('qux')
>>> x
{'bar', 'baz', 'foo', 'qux'}
複製代碼
x.remove() 刪除元素
若是刪除的元素不存在會拋出異常
>>> x = {'foo', 'bar', 'baz'}
>>> x.remove('baz')
>>> x
{'bar', 'foo'}
>>> x.remove('qux')
Traceback (most recent call last):
File "<pyshell#58>", line 1, in <module>
x.remove('qux')
KeyError: 'qux'
複製代碼
這個時候爲了不出現錯誤能夠用discard方法
>>> x = {'foo', 'bar', 'baz'}
>>> x.discard('baz')
>>> x
{'bar', 'foo'}
>>> x.discard('qux')
>>> x
{'bar', 'foo'}
複製代碼
利用pop刪除隨機元素並返回:
>>> x = {'foo', 'bar', 'baz'}
>>> x.pop()
'bar'
>>> x
{'baz', 'foo'}
>>> x.pop()
'baz'
>>> x
{'foo'}
>>> x.pop()
'foo'
>>> x
set()
複製代碼
利用clear能夠清空一個集合:
>>> x = {'foo', 'bar', 'baz'}
>>> x
{'foo', 'bar', 'baz'}
>>>
>>> x.clear()
>>> x
set()
複製代碼
Frozen Sets是什麼東西
Python提供了另外一種稱爲凍結集合Frozen Sets的內置類型,它在全部方面都與集合徹底相同,只不過Frozen Sets是不可變的。咱們能夠對凍結集執行非修改操做,好比:
>>> x = frozenset(['foo', 'bar', 'baz'])
>>> x
frozenset({'foo', 'baz', 'bar'})
>>> len(x)
3
>>> x & {'baz', 'qux', 'quux'}
frozenset({'baz'})
複製代碼
若是膽敢嘗試修改Frozen Sets:
>>> x = frozenset(['foo', 'bar', 'baz'])
>>> x.add('qux')
Traceback (most recent call last):
File "<pyshell#127>", line 1, in <module>
x.add('qux')
AttributeError: 'frozenset' object has no attribute 'add'
>>> x.pop()
Traceback (most recent call last):
File "<pyshell#129>", line 1, in <module>
x.pop()
AttributeError: 'frozenset' object has no attribute 'pop'
>>> x.clear()
Traceback (most recent call last):
File "<pyshell#131>", line 1, in <module>
x.clear()
AttributeError: 'frozenset' object has no attribute 'clear'
>>> x
frozenset({'foo', 'bar', 'baz'})
複製代碼
基本使用舉例
Frozensets在咱們想要使用集合的狀況下頗有用,但須要一個不可變對象。 例如,若是沒有Frozen sets咱們不能定義其元素也是集合的集合(nested),由於集合元素必須是不可變的,會報錯:
>>> x1 = set(['foo'])
>>> x2 = set(['bar'])
>>> x3 = set(['baz'])
>>> x = {x1, x2, x3}
Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
x = {x1, x2, x3}
TypeError: unhashable type: 'set'
複製代碼
如今有了 Frozen sets,咱們有了解決方案:
>>> x1 = frozenset(['foo'])
>>> x2 = frozenset(['bar'])
>>> x3 = frozenset(['baz'])
>>> x = {x1, x2, x3}
>>> x
{frozenset({'bar'}), frozenset({'baz'}), frozenset({'foo'})}
複製代碼
但願這期總結的有關Set的經常使用方法能夠幫到你們,若是喜歡,就點贊把~