歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Python數據類型之“集合(Sets)與映射(Mapping)”

Python數據類型之“集合(Sets)與映射(Mapping)”

日期:2017/3/1 9:08:04   编辑:Linux編程

一、集合類型(Sets)


集合對象是不同的(不可重復)hashable對象的無序集合。常見用法包括:成員關系測試、移除序列中的重復、以及科學計算,例如交集、並集、差分和對稱差分。通俗點來說,集合是一個無序不重復元素的數據集,其基本功能是進行成員關系測試和消除重復元素。

目前有兩種內置的集合類型:set 和 frozenset。set類型是可變的--可以使用add() 和 remove()等方法更改其內容。由於它是可變的,它沒有hash值,因此它不能被當做字典的鍵值或另一集合的元素。frozenset類型是不可變的 和 hashable的,它的內容不能再創建後改變,因此它可以用作字典的鍵值或作為另一個集合的元素。

set類構建函數

class set([iterable])
class frozenset([iterable])

set的構建方式

  • 將一個用逗號分割的元素列表放在一堆花括號內可以創建一個非空set集合,如{'Tom', 'Jerry', 'Peter'}
  • 給set的構建函數傳遞一個空值將會創建一個空set集合(注意:{}表示的是一個空字典而不是空set集合)
  • 給set的構架你函數傳一個非空iterable參數將會創建一個非空set集合

注意:

再次強調,一個set集合內的元素必須是hashable的(不可變的)。要想表示一個set的set,那麼內部的set必須是frozenset對象,因為frozenset是不可變的,是hashable的。

set構建示例

>>> {'Tom', 'Jerry', 'Peter'}  # 使用花括號創建非空set集合
{'Jerry', 'Tom', 'Peter'}
>>> set()  # 使用set構建函數創建空set集合
set()
>>> set((1, 2, 3 ,4))  # 使用set構建函數創建非空set集合
{1, 2, 3, 4}
>>> set((1, 2, 3 ,['a', 'b', 'c']))  # set集合中的元素必須是不可變的、可哈希的
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

set 和 frozenset都支持的操作

作為無序集合,set不記錄元素位置或插入順序。因此set不支持索引、切片或其他類序列行為。

len(set)  # 獲取集合中的條目個數
x in set  # 成員關系測試--包含
x not in set # 成員關系測試--不包含
for x in set  # 循環遍歷集合中的條目
isdisjoint(other)  # 判斷該集合是否與另外一個集合不相交(當且僅當交集為空),不相交則返回True
issubset(other) 或 set <= other  # 判斷該集合是否是另外一個集合的子集
set < other  # 判斷該集合是否是另外一個集合的真子集
issuperset(other) 或 set >= other  # 判斷該集合是否是另外一個集合的父集
set > other  # 判斷該集合是否是另外一個集合的真父集
union(other,...) 或 set | other | ...  # 求該集合與另外一個或多個集合的並集
intersection(other,...) 或 set & other & ...  # 求該集合與另外一個或多個集合的交集
difference(other,...) 或 set - other - ...  # 求該集合與另外一個或多個集合的差集(該集合中存在但其它集合中不存在的元素集合)
symmetric_difference(other) 或 set ^ other  # 求該集合與另外一個集合的對稱差集(該集合中存在但另一集合中不存在,或另一集合中存在但該集合中不存在的元素集合)
copy()  # 返回一個新的淺拷貝集合

說明:

a) union()、intersection()、differnce()、symmetric_difference()、issubset() 和 issuperset()方法的可接受任何可迭對象作為參數。相比之下,它們的基於運算符的相應操作需要它們的參數是set。這避免了像set('abc') & 'cbs'這樣易出錯的結構,有利於更易讀的結構,如set('abc').intersection('cbs')。

>>> set('abc')
{'c', 'a', 'b'}
>>> set('abc') & 'cbs'  # 使用操作符進行相關操作,操作符兩邊都必須是set類型
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'set' and 'str'
>>> set('abc') & set('cbs')
{'c', 'b'}
>>> set('abc').intersection('cbs')  # 調用方法進行相關操作,參數可以是任意可迭代對象
{'c', 'b'}
>>> set('abc').intersection(['c','s', 'b'])
{'c', 'b'}

b) set和frozenset支持 集合與集合進行比較操作。

  • 當且僅當每個集合的每個元素都包含在另一個(每個集合都是另一個的子集)時,兩個集合是相等的;
  • 當且僅當第一集合是第二集合的真子集(是子集,但不相等)時,集合小於另一集合;
  • 當且僅當第一集合是第二集合的真父集(是父集,但不相等)時,集合大於另一集合;

c) set和frozenset之間是基於它們的成員進行比較的。比如set('abc') == frozenset('abc')返回True,因此set('abc') in set([frozenset('abc')])

>>> set('abc') == frozenset('abc')
True
>>> set('abc') in frozenset('abc')
False
>>> set('abc') in set(frozenset('abc'))
False
>>> set('abc') in set([frozenset('abc')])
True

d) 子集和相等的比較不推廣到總排序函數。例如,任何兩個非空且不相交的集合是不相等的,並且不是彼此的子集。因此,它們對應的以下操作都返回False: a<b, a==b, a>b。

e) 因為set之定義了部分排序(子集關系),因此滅有為set的list定義list.sort()方法。

f) set集合的元素像dict的鍵一樣,必須是可哈希的。

g) set實例與frozenset實例混合進行二進制操作將會返回第一個操作數的類型。例如:frozenset('ab')
| set('bc')會返回一個frozenset實例。

set支持但frozenset不支持的操作

set是可變集合,而frozenset是不可變集合,因此set的有些修改操作是frozenset不支持的。

add(elem)  # 向集合中添加一個元素
remove(elem)  # 從集合中刪除一個元素,如果集合中不包含該元素會拋出KeyError錯誤
discard(elem)  # 如果集合中包含該元素則刪除它,這個方法明顯比remove()好用
pop()  # 由於set集合是無序的,因此該方法會移除並返回一個隨機元素,而不是像list.pop()移除並返回最後一個元素
clear()  # 清除set集合中的所有元素
update(other,...) 或 set |= other | ...  # 更新set集合,將其它集合中的元素添加進來;簡單點來說就是與其它一個或多個集合求並集並將結果賦值給自己
intersection_update(other,...) 或 set &= other & ...  # 更新set集合,只保留所有集合中都存在的元素;簡單點來說就是與其它一個或多個集合求交集並將結果賦值為自己
difference_update(other,...) 或 set -= other | ...  # 與其它一個或多個集合求差集並將結果賦值給自己
symmetric_difference_update(other) 或 set ^= other  # 與另外一個集合求對稱差集並將結果賦值給自己;對稱差集就是A-B 與 B-A 的並集

說明:

上面這些update方法也是可以接受任何可迭代對象作為參數。另外,remove(elem)和discard(elem)等方法中參數elem可以是一個set集合。為了支持搜索等效的frozenset,elem集合會在搜索期間被暫時修改,然後恢復。在搜索期間,elem不應該被讀取或改動,因為它沒有有意義的值。

二、映射類型(mapping)


一個mapping對象將可哈希的值映射為任意對象。映射是可變對象。目前Python中只有一種標准映射類型,就是字典(dict)。dcit和Set集合一樣也是用花括號表示,但是花括號中的每個元素都是一個鍵值對(key:value)。字典中的鍵值對也是無序的,且key必須是可哈希的不可變類型,如字符串、數字、布爾值和不包含可變類型的tuple。而list和包含可變類型的tuple是不能做字典的key的。另外,同一個字典中,key不能重復,否則會覆蓋之前的值。、

用於鍵的數字類型遵守數字比較的正常規則:如果兩個數字比較相等(比如1和1.0),則它們可以互相使用以索引相同的字典條目。但是需要注意,由於計算機存儲浮點數作為近似值,因此使用它們作為字典的鍵通常是不明智的。

dict類構建函數

class dict(**kwarg)
class dict(mapping, **kwarg)
class dict(iterable, **kwarg)

上面的dict構建函數會返回一個新的字典,這個新的字典是從一個可選的位置參數和一組可能為空關鍵字參數初始化的。

dict的構建方式

  • 將以逗號分隔的 key:value (鍵值對)列表放置在一對花括號中:{},{'Tom':1, 'Jerry':2, 'Peter':3}
  • 使用不傳遞位置參數的構建函數,創建空字典:dict(),等同於{}
  • 如果給定了位置參數,並且它是映射對象,則使用與該映射對象相同的鍵值對創建字典;否則,位置參數必須是可迭代對象。可迭代對象中的每個條目本身必須是具有兩個對象的可迭代對象。每個條目的第一個對象將會成為新字典中的鍵,第二個對象將會成為對應的值。如果鍵多次出現,則該鍵的最後一個值將成為新字典中的相應值。
  • 如果給出了關鍵字參數,則將關鍵字參數及其值添加到從位置參數創建的字典中。如果要添加的鍵已經存在,則來自關鍵字參數的值將替換位置參數中的值。

dict構建示例

空字典

>>> a = {}
>>> a
{}
>>> b = dict()
>>> b
{}
>>> a == b
True

非空字典

>>> a = {'one': 1, 'two': 2, 'three': 3}  # 將以逗號分隔的鍵值對列表放置在一對花括號中
>>> b = dict(one=1, two=2, three=3)  # 使用dict構建函數,並傳遞關鍵字參數
>>> c = dict([('two', 2), ('one', 1), ('three', 3)])  # 使用dict構建函數,並傳遞可迭代對象為位置參數
>>> d = dict({'three': 3, 'two': 2, 'one': 1})  # 使用dict構建函數,並傳遞可迭代對象作為位置參數
>>> e = dict({'three': 3, 'two': 2, 'one': 1}, four=4, five=5)  # 使用dict構建函數,同時傳遞可迭代位置參數和關鍵字參數
>>> e
{'five': 5, 'two': 2, 'three': 3, 'one': 1, 'four': 4}
>>> a == b == c == d
True

關於[('one', 1), ('two', 2), ('three', 3)]這種格式的列表我們可以通過zip類來創建(zip在Python 2.x中是一個內建函數,而在Python 3.x中是一個類),zip類的構建函數如下:

zip(iter1 [,iter2 [...]])

為了方便查看效果,我們使用Python 2.x來做下實驗:

>>> zip(['one', 'two', 'three'], [1, 2, 3])
[('one', 1), ('two', 2), ('three', 3)]
>>> zip(['one', 'two', 'three'], [1, 2, 3], ('I', 'II', 'III'))
[('one', 1, 'I'), ('two', 2, 'II'), ('three', 3, 'III')]
>>> zip(['one', 'two', 'three', 'four'], [1, 2, 3, 4], ('I', 'II', 'III'))  # 結果中的條目數與此處條目數最少的可迭代對象一致
[('one', 1, 'I'), ('two', 2, 'II'), ('three', 3, 'III')]

dict支持的操作

len(d)  # 返回字典d中的條目數
key in d  # 如果字典d中包含key這個鍵則返回True, 否則返回False
key not in d  # 與上面剛好相反

d[key]  # 返回key對應的條目的值,如果key不存在會拋出KeyError異常
get(key[, default])  # 如果key存在則返回其對應的值,否則返回default參數指定的值。如果default沒有被指定,則default取None,因此該方法永遠不會拋出KeyError異常。
setdefault(key[,default])  # 如果key存在則返回這個key對應的值,如果key不存在則插入一個鍵值對key:default並返回default的值。default默認值為None。
classmethod fromkeys(seq[,value]) # 這是個類方法,用於創建一個新的字典。seq序列中的元素將作為新字典中的key,而value將會是這些key共同的值,value默認為None。

copy()  # 返回該dict的一個淺拷貝

keys()  # 返回一個字典鍵的新視圖
values()  # 返回一個字典值的新視圖
items()  # 返回一個字典條目的新視圖:(key, value)
iter(d)  # 返回字典鍵的一個迭代器,這是iter(d.keys())的簡寫方式

d[key] = value # 如果key不存在則表示新增一個條目,如果key已經存在則表示修改該條目的值
update([other])  # 用other中的鍵值對更新字典的內容,覆蓋現有的key。other可以是一個字典對象或鍵/值對(比如長度為2的元組或其它可迭代對象)。如果指定了關鍵字參數,字典將會使用關鍵字參數對字典的鍵/值對更新,如:d.update(紅色=1, 藍色=2)

del d[key]  # 刪除key對應的表木,如果key不存在會拋出KeyError異常
popitem()  # 從字典中刪除並返回一個任意(key, value)對,如果字典為空會拋出KeyError異常。該方法對於破壞性的遍歷字典很有用,常用於集合算法。
pop(key[,default])  # 如果key存在就刪除它並返回它的值,否則返回default的值。如果default沒有被給出並且key不存在,則拋出KeyError異常。
clear()  # 清空dict中的所有條目

操作示例

>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> len(d)
3
>>> 'two' in d
True
>>> 'two' not in d
False
>>>
>>> d['three']
3
>>> d['four']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'four'
>>> d.get('three')
3
>>> d.get('four', 'default')
'default'
>>> d
{'one': 1, 'two': 2, 'three': 3}
>>> d.setdefault('three', 'default')
3
>>> d
{'one': 1, 'two': 2, 'three': 3}
>>> d.setdefault('four', 'default')
'default'
>>> d
{'one': 1, 'two': 2, 'four': 'default', 'three': 3}
>>> dict.fromkeys(['one', 'two', 'three'])
{'one': None, 'two': None, 'three': None}
>>> dict.fromkeys(['one', 'two', 'three'], 'default')
{'one': 'default', 'two': 'default', 'three': 'default'}
>>>
>>> d.copy()
{'one': 1, 'two': 2, 'four': 'default', 'three': 3}
>>> d['four'] = 4
>>> d
{'one': 1, 'two': 2, 'four': 4, 'three': 3}
>>> d['five'] = 5
>>> d
{'one': 1, 'two': 2, 'five': 5, 'four': 4, 'three': 3}
>>> d.update({'two': 'II', 'six': 6})
>>> d
{'one': 1, 'two': 'II', 'four': 4, 'five': 5, 'six': 6, 'three': 3}
>>> d.update(two=2, seven=7)
>>> d
{'one': 1, 'two': 2, 'four': 4, 'five': 5, 'six': 6, 'seven': 7, 'three': 3}
>>> d.update([('three', 'III'), ('eight', 8)])
>>> d
{'one': 1, 'two': 2, 'four': 4, 'five': 5, 'eight': 8, 'six': 6, 'seven': 7, 'three': 'III'}
>>>
>>> d.keys()
dict_keys(['one', 'two', 'four', 'five', 'eight', 'six', 'seven', 'three'])
>>> d.values()
dict_values([1, 2, 4, 5, 8, 6, 7, 'III'])
>>> d.items()
dict_items([('one', 1), ('two', 2), ('four', 4), ('five', 5), ('eight', 8), ('six', 6), ('seven', 7), ('three', 'III')])
>>> iter(d)
<dict_keyiterator object at 0x000001EA21A179A8>
>>> iter(d.keys())
<dict_keyiterator object at 0x000001EA21A175E8>
>>>
>>> del d['eight']
>>> d
{'one': 1, 'two': 2, 'four': 4, 'five': 5, 'six': 6, 'seven': 7, 'three': 'III'}
>>> d.popitem()
('one', 1)
>>> d
{'two': 2, 'four': 4, 'five': 5, 'six': 6, 'seven': 7, 'three': 'III'}
>>> d.pop('three')
'III'
>>> d
{'two': 2, 'four': 4, 'five': 5, 'six': 6, 'seven': 7}
>>> d.pop('three')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'three'
>>> d.pop('three',None)
>>> d.pop('three','default')
'default'
>>> d.clear()
>>> d.popitem()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'popitem(): dictionary is empty'

字典視圖對象(Dictionary view objects)

對於dict.keys()、dict.values()和dict.items()這些函數,在Python 2.x中返回的是list對象,而在Python 3.x中返回的是一個叫做字典視圖的對象。

python 2.x

>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> d.keys()
['three', 'two', 'one']
>>> d.values()
[3, 2, 1]
>>> d.items()
[('three', 3), ('two', 2), ('one', 1)]

python 3.x

>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> dkeys = d.keys()
>>> dkeys
dict_keys(['one', 'three', 'two'])
>>> dvalues = d.values()
>>> dvalues
dict_values([1, 3, 2])
>>> ditems = d.items()
>>> ditems
dict_items([('one', 1), ('three', 3), ('two', 2)])

字典視圖在字典條目上提供了一個動態視圖,這意味著當字典發生變化時,相應的視圖也會發生變化。要保存固定的值需要將字典視圖強制轉換為其他類型的對象進行保存,通常保存為list類型。

>>> d['four'] = 4
>>> d
{'one': 1, 'three': 3, 'two': 2, 'four': 4}
>>> dkeys
dict_keys(['one', 'three', 'two', 'four'])
>>> dvalues
dict_values([1, 3, 2, 4])
>>> ditems
dict_items([('one', 1), ('three', 3), ('two', 2), ('four', 4)])

Copyright © Linux教程網 All Rights Reserved