我們知道,Python 的數(shù)據(jù)類型有 list, tuple, dict, str 等,collections 模塊提供了額外 5 個高性能的數(shù)據(jù)類型:
Counter: 計數(shù)器OrderedDict: 有序字典defaultdict: 帶有默認值的字典namedtuple: 生成可以通過屬性訪問元素內(nèi)容的 tuple 子類deque: 雙端隊列,能夠在隊列兩端添加或刪除元素Counter 是一個簡單的計數(shù)器,可用于統(tǒng)計字符串、列表等的元素個數(shù)。
看看例子:
>>> from collections import Counter
>>>
>>> s = 'aaaabbbccd'
>>> c = Counter(s) # 創(chuàng)建了一個 Counter 對象
>>> c
Counter({'a': 4, 'b': 3, 'c': 2, 'd': 1})
>>> isinstance(c, dict) # c 其實也是一個字典對象
True
>>> c.get('a')
4
>>> c.most_common(2) # 獲取出現(xiàn)次數(shù)最多的前兩個元素
[('a', 4), ('b', 3)]
在上面,我們使用 Counter() 創(chuàng)建了一個 Counter 對象 c,Counter 其實是 dict 的一個子類,我們可以使用 get 方法來獲取某個元素的個數(shù)。Counter 對象有一個 most_common 方法,允許我們獲取出現(xiàn)次數(shù)最多的前幾個元素。
另外,兩個 Counter 對象還可以做運算:
>>> from collections import Counter
>>>
>>> s1 = 'aaaabbbccd'
>>> c1 = Counter(s1)
>>> c1
Counter({'a': 4, 'b': 3, 'c': 2, 'd': 1})
>>>
>>> s2 = 'aaabbef'
>>> c2 = Counter(s2)
>>> c2
Counter({'a': 3, 'b': 2, 'e': 1, 'f': 1})
>>>
>>> c1 + c2 # 兩個計數(shù)結(jié)果相加
Counter({'a': 7, 'b': 5, 'c': 2, 'e': 1, 'd': 1, 'f': 1})
>>> c1 - c2 # c2 相對于 c1 的差集
Counter({'c': 2, 'a': 1, 'b': 1, 'd': 1})
>>> c1 & c2 # c1 和 c2 的交集
Counter({'a': 3, 'b': 2})
>>> c1 | c2 # c1 和 c2 的并集
Counter({'a': 4, 'b': 3, 'c': 2, 'e': 1, 'd': 1, 'f': 1})
Python 中的 dict 是無序的:
>>> dict([('a', 10), ('b', 20), ('c', 15)])
{'a': 10, 'c': 15, 'b': 20}
有時,我們希望保持 key 的順序,這時可以用 OrderedDict:
>>> from collections import OrderedDict
>>> OrderedDict([('a', 10), ('b', 20), ('c', 15)])
OrderedDict([('a', 10), ('b', 20), ('c', 15)])
在 Python 中使用 dict 時,如果訪問了不存在的 key,會拋出 KeyError 異常,因此,在訪問之前,我們經(jīng)常需要對 key 作判斷,比如:
>>> d = dict()
>>> s = 'aaabbc'
>>> for char in s:
... if char in d:
... d[char] += 1
... else:
... d[char] = 1
...
>>> d
{'a': 3, 'c': 1, 'b': 2}
使用 defaultdict,我們可以給字典中的 key 提供一個默認值。訪問 defaultdict 中的 key,如果 key 存在,就返回 key 對應(yīng)的 value,如果 key 不存在,就返回默認值。
>>> from collections import defaultdict
>>> d = defaultdict(int) # 默認的 value 值是 0
>>> s = 'aaabbc'
>>> for char in s:
... d[char] += 1
...
>>> d
defaultdict(<type 'int'>, {'a': 3, 'c': 1, 'b': 2})
>>> d.get('a')
3
>>> d['z']
0
使用 defaultdict 時,我們可以傳入一個工廠方法來指定默認值,比如傳入 int,表示默認值是 0,傳入 list,表示默認是 []:
>>> from collections import defaultdict
>>>
>>> d1 = defaultdict(int)
>>> d1['a']
0
>>> d2 = defaultdict(list)
>>> d2['b']
[]
>>> d3 = defaultdict(str)
>>> d3['a']
''
我們還可以自定義默認值,通過 lambda 函數(shù)來實現(xiàn):
>>> from collections import defaultdict
>>>
>>> d = defaultdict(lambda: 10)
>>> d['a']
10
我們經(jīng)常用 tuple (元組) 來表示一個不可變對象,比如用一個 (姓名, 學號, 年齡) 的元組來表示一個學生:
>>> stu = ('ethan', '001', 20)
>>> stu[0]
'ethan'
這里使用 tuple 沒什么問題,但可讀性比較差,我們必須清楚索引代表的含義,比如索引 0 表示姓名,索引 1 表示學號。如果用類來定義,就可以通過設(shè)置屬性 name, id, age 來表示,但就有些小題大作了。
我們可以通過 namedtuple 為元組的每個索引設(shè)置名稱,然后通過「屬性名」來訪問:
>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['name', 'id', 'age']) # 定義了一個 Student 元組
>>>
>>> stu = Student('ethan', '001', 20)
>>> stu.name
'ethan'
>>> stu.id
'001'
deque 是雙端隊列,允許我們在隊列兩端添加或刪除元素。
>>> from collections import deque
>>> q = deque(['a', 'b', 'c', 'd'])
>>> q.append('e') # 添加到尾部
>>> q
deque(['a', 'b', 'c', 'd', 'e'])
>>> q.appendleft('o') # 添加到頭部
>>> q
deque(['o', 'a', 'b', 'c', 'd', 'e'])
>>> q.pop() # 從尾部彈出元素
'e'
>>> q
deque(['o', 'a', 'b', 'c', 'd'])
>>> q.popleft() # 從頭部彈出元素
'o'
>>> q
deque(['a', 'b', 'c', 'd'])
>>> q.extend('ef') # 在尾部 extend 元素
>>> q
deque(['a', 'b', 'c', 'd', 'e', 'f'])
>>> q.extendleft('uv') # 在頭部 extend 元素,注意順序
>>> q
deque(['v', 'u', 'a', 'b', 'c', 'd', 'e', 'f'])
>>>
>>> q.rotate(2) # 將尾部的兩個元素移動到頭部
>>> q
deque(['e', 'f', 'v', 'u', 'a', 'b', 'c', 'd'])
>>> q.rotate(-2) # 將頭部的兩個元素移動到尾部
>>> q
deque(['v', 'u', 'a', 'b', 'c', 'd', 'e', 'f'])
其中,rotate 方法用于旋轉(zhuǎn),如果旋轉(zhuǎn)參數(shù) n 大于 0,表示將隊列右端的 n 個元素移動到左端,否則相反。