Python 中的 Counter 模塊及使用詳解(搞定重復計數)

參考

項目 描述
Python 標準庫 DougHellmann  / 劉熾 等 
搜索引擎 Bing
Python 官方文檔 collections — 容器數據類型

描述

項目 描述
Python 解釋器 3.10.6

Counter 模塊

在 Python 的 collections 模塊中,有一個很常用的模塊就是 Counter。Counter 是一個簡單的計數器,用於統計某些可哈希對象的數量。它以字典的形式存儲元素和它們的計數。

Counter() 類

Counter() 能夠對傳入給該類的參數按照一定規則進行計數,並將計數對象與計數結果作為鍵值對以字典的形式進行結果的返回。

Counter(iterable=None, /, **kwds)

舉個栗子

from collections import Counter
# 返回一個空的 Counter 對象
cnt = Counter()
print(cnt)

# 將可迭代對象(字符串)作為參數
cnt = Counter('Hello World')
print(cnt)

# 將可迭代對象(列表)作為參數
cnt = Counter(['a', 'a', 'b', 'd', 'c', 'd'])
print(cnt)

# 使用可迭代對象(字典)作為參數
cnt = Counter({'a': 1, 'b': 2, 'd': 3, 'c': 2})
print(cnt)

# 使用關鍵字參數
cnt = Counter(a=1, b=2, d=3, c=2)
print(cnt)

執行效果

Counter()
Counter({'l': 3, 'o': 2, 'H': 1, 'e': 1, ' ': 1, 'W': 1, 'r': 1, 'd': 1})
Counter({'a': 2, 'd': 2, 'b': 1, 'c': 1})
Counter({'d': 3, 'b': 2, 'c': 2, 'a': 1})
Counter({'d': 3, 'b': 2, 'c': 2, 'a': 1})

Counter() 對象

字典

Counter() 返回的結果為一個字典,它擁有普通字典的大部分方法。在大多數情況下,你可以像操作字典一樣操作 Counter 對象。對此,請參考如下示例:

from collections import Counter
cnt = Counter('Hello World')
print(cnt)

# 輸出 Counter 對象中的鍵值對列表
print(cnt.items())

# 移除 Counter 對象中的最後一個鍵值對
print(cnt.popitem())
print(cnt)

# 輸出 Counter 中鍵 l 對應的值
print(cnt['l'])

執行結果

Counter({'l': 3, 'o': 2, 'H': 1, 'e': 1, ' ': 1, 'W': 1, 'r': 1, 'd': 1})
dict_items([('H', 1), ('e', 1), ('l', 3), ('o', 2), (' ', 1), ('W', 1), ('r', 1), ('d', 1)])
('d', 1)
Counter({'l': 3, 'o': 2, 'H': 1, 'e': 1, ' ': 1, 'W': 1, 'r': 1})
3

有序性

Python 中的字典是無序的,無序的 的含義並不是說字典中的鍵值對沒有順序,而是指字典中的鍵值對的順序是不可預測的。對此,請參考如下示例:

d = {'a': 1, 'b': 2, 'c': 3}
for key in d:
    print(key)

該示例的輸出結果可能是:

a
b
c

也可能是:

b
c
a

當然還存在其他可能,這裡就不一一列舉瞭。

Python 官方對 Python 3.6 版本中的字典進行瞭優化,使其能夠記住鍵值對插入的順序。此後,字典顯得不那麼凌亂瞭(字典中的鍵值對的順序變得可以預測瞭)。

KeyError

在 Python 的內置字典中,若嘗試訪問不存在的鍵,Python 將拋出 KeyError 異常錯誤。對此,請參考如下示例:

d = dict([('a', 1), ('b', 2), ('c', 3)])
print(d)

# 嘗試訪問字典 d 中不存在的鍵
print(d['d'])

執行效果

Traceback (most recent call last):
  File "C:\main.py", line 5, in <module>
    print(d['d'])
KeyError: 'd'
{'a': 1, 'b': 2, 'c': 3}

同樣的場景。這一次,我們讓 Counter 作為主角。

from collections import Counter
cnt = Counter({'a': 1, 'b': 2, 'c': 3})
print(cnt)

# 嘗試訪問 Counter 中不存在的鍵
print(cnt['d'])

執行效果

訪問 Counter 對象中不存在的鍵時,並不會拋出 KeyError 異常,而是返回默認計數值 0

Counter({'c': 3, 'b': 2, 'a': 1})
0

魔術方法 __missing__

__missing__() 是 Python 中的一個特殊方法,用於處理通過鍵訪問字典中的值時鍵不存在時的情況。
當我們使用字典的索引來訪問一個不存在的鍵時,Python 將會調用特殊方法 __missing__() 來嘗試返回一個合適的值。若未實現 __missing__() 方法,Python 將會拋出 KeyError 異常。對此,請參考如下示例:

# 創建一個字典對象,該對象繼承自 Python 內置的 dict 對象
class MyDict(dict):
    def __missing__(self, key):
        return 0

# 實例化 MyDict() 對象
myDict = MyDict()
# 嘗試訪問 myDict 對象中不存在的鍵 a
print(myDict['a'])

執行效果

0

update() 方法

Counter 對象與 dict 對象同樣實現瞭 update() 方法。使用 update() 方法能夠將作為參數的字典合並到調用該方法的 dict 對象中。不同的是,dict 對象的 update() 方法在遇到具有相同的鍵時,將會對該鍵對應的值執行 覆蓋 操作。而 Counter 對象的 update() 方法在遇到具有相同的鍵時,將會對該鍵對應的值執行 疊加 操作。對此,請參考如下示例:

from collections import Counter
# Python 中內置的 dict 對象
d = dict([('a', 1), ('b', 2), ('c', 3)])
print(d)

d.update({'a': 4})
print(d)

print()

# Counter 對象
cnt = Counter({'a': 1, 'b': 2, 'c': 3})
print(cnt)

cnt.update({'a': 4})
print(cnt)

執行效果

{'a': 1, 'b': 2, 'c': 3}
{'a': 4, 'b': 2, 'c': 3}

Counter({'c': 3, 'b': 2, 'a': 1})
Counter({'a': 5, 'c': 3, 'b': 2})

Counter 對象的常用方法

most_common()

most_common() 方法將返回一個列表,列表中的元素均為 Counter 對象中的鍵值對組成的元組。元組在列表中的順序取決於計數值(鍵值對中的值)的大小。計數值更大的元組將位於列表的前端,計數值相等的元組將按照它們首次在列表中出現的順序進行排列(先出現的元組將更靠近列表的前端)。
most_common() 默認將使用 Counter 對象中所有的鍵值對組成的元組作為返回列表中的元素。你可以通過向該方法提供一個數值,該數值將指定放回的列表中的元素的數量。

舉個栗子

from collections import Counter
cnt = Counter({'a': 1, 'b': 2, 'c': 3})
print(cnt)

print()

print(cnt.most_common())
# 返回由 Counter 中計數值最大的兩個
# 鍵值對構成的元組所組成的列表
print(cnt.most_common(2))
# 返回由 Counter 中計數值最大的
# 鍵值對構成的元組所組成的列表
print(cnt.most_common(1))

執行效果

Counter({'c': 3, 'b': 2, 'a': 1})

[('c', 3), ('b', 2), ('a', 1)]
[('c', 3), ('b', 2)]
[('c', 3)]

elements()

elements() 方法將返回一個以 Counter 對象中的鍵為元素的迭代器,其中每個元素將重復出現計數值所指定的次數。

迭代器中的元素將存在如下特點:

  • 元素將會按照其首次添加到 Counter 對象中的順序進行返回。
  • 某個鍵對應的計數值小於一,那麼該鍵將不會作為元素出現在 element() 方法返回的迭代器中。

舉個栗子

from collections import Counter
cnt = Counter({'a': 1, 'b': 2, 'c': 3, 'd': -4})
print(cnt)

print()

print(list(cnt.elements()))

執行效果

Counter({'c': 3, 'b': 2, 'a': 1, 'd': -4})

['a', 'b', 'b', 'c', 'c', 'c']

total()

total() 方法將返回 Counter 對象中,所有計數值累加後得到的結果。對此,請參考如下示例:

from collections import Counter
cnt = Counter({'a': 1, 'b': 2, 'c': 3, 'd': -4})
cnt1 = Counter('Hello World')
print(cnt.total())
print(cnt1.total())

執行效果

2
11

subtract()

該方法的效果與 Counter 對象的 update() 方法類似。如果說 update() 方法執行的是 操作,那麼 subtract() 方法執行的則是 操作。對此,請參考如下示例:

from collections import Counter
cnt = Counter({'a': 1, 'b': 2, 'c': 3, 'd': -4})

cnt.subtract({'a': 0, 'b': 1, 'd': -11})
print(cnt)

執行效果

Counter({'d': 7, 'c': 3, 'a': 1, 'b': 1})

Counter 對象間的運算

註:

本部分內容中講解到的運算符僅能在 Python 3.3 及以後版本中正常使用。

加法運算

在 Python 的 Counter 模塊中,兩個 Counter 對象可以相加,相加後將返回一個新的 Counter 對象,其中每個元素的計數是兩個原始 Counter 對象中該元素計數的總和。可以通過使用加法運算符來執行此操作。對此,請參考如下示例:

from collections import Counter

cnt = Counter('Hello')
cnt1 = Counter('World')

print(cnt)
print(cnt1)
print(cnt + cnt1)

執行效果

Counter({'l': 2, 'H': 1, 'e': 1, 'o': 1})
Counter({'W': 1, 'o': 1, 'r': 1, 'l': 1, 'd': 1})
Counter({'l': 3, 'o': 2, 'H': 1, 'e': 1, 'W': 1, 'r': 1, 'd': 1})

註:

在 Counter 對象間的運算過程中,對於 Counter 中不存在的鍵,其計數值為零。

減法運算

在 Python 的 Counter 模塊中,可以使用減法運算符來對兩個 Counter 對象進行減法運算,即將左側 Counter 對象中的計數器值減去右側 Counter 對象中相同鍵的計數器值,最後返回一個新的 Counter 對象。對此,請參考如下示例:

from collections import Counter

cnt = Counter('cook')
cnt1 = Counter('coder')

print(cnt)
print(cnt1)
print(cnt - cnt1)

執行效果

Counter({'o': 2, 'c': 1, 'k': 1})
Counter({'c': 1, 'o': 1, 'd': 1, 'e': 1, 'r': 1})
Counter({'o': 1, 'k': 1})

註:

在 Counter 對象間的運算過程中,對於 Counter 中不存在的鍵,其計數值為零。

並集運算

Counter 對象之間的並集運算是指兩個 Counter 對象按照鍵的並集進行運算,返回的結果是一個新的 Counter 對象,其中包含的鍵和值均為 原始 Counter 對象中存在的鍵及其對應的最大值。對此,請參考如下示例:

from collections import Counter

cnt = Counter('Hello')
cnt1 = Counter('World')

print(cnt)
print(cnt1)
print(cnt | cnt1)

執行效果

Counter({'l': 2, 'H': 1, 'e': 1, 'o': 1})
Counter({'W': 1, 'o': 1, 'r': 1, 'l': 1, 'd': 1})
Counter({'l': 2, 'H': 1, 'e': 1, 'o': 1, 'W': 1, 'r': 1, 'd': 1})

交集運算

Counter 對象之間的交集運算是指兩個 Counter 對象按照鍵的交集進行運算,返回的結果是一個新的 Counter 對象,其中包含的鍵和值均為 原始 Counter 對象中共同擁有的鍵及其對應的最小值。對此,請參考如下示例:

from collections import Counter

cnt = Counter('Hello')
cnt1 = Counter('World')

print(cnt)
print(cnt1)
print(cnt & cnt1)

執行效果

Counter({'l': 2, 'H': 1, 'e': 1, 'o': 1})
Counter({'W': 1, 'o': 1, 'r': 1, 'l': 1, 'd': 1})
Counter({'l': 1, 'o': 1})

單目運算

單目運算指的是表達式中存在單目運算符的運算操作。存在兩種單目運算符,即單目減法運算符與單目加法運算符。無論是單目減法運算符還是單目加法運算符,它們的操作對象均為 Counter 對象中的計數值。
在對 Counter 對象進行單目運算後,將返回一個由大於零的計數值相關的鍵值對組成的 Counter 對象。對此,請參考如下示例:

from collections import Counter

cnt = Counter({'a': 4, 'b': 3, 'd': 0, 'c': -5})
print(+cnt)
print(-cnt)

執行效果

Counter({'a': 4, 'b': 3})
Counter({'c': 5})

Counter 對象間的比較

Python 3.10 版本開始,Counter 對象間開始支持常見的比較運算符,這些運算符有:

  • <
  • <=
  • >
  • >=
  • ==
  • !=

這裡以 >== 為例進行講解。

>

> 的左側的 Counter 對象的鍵對應的計數值均大於該符號右側的 Counter 對象中相同的鍵(對於 Counter 中不存在的鍵,其計數值為零)對應的計數值時,比較結果為 True。否則為 False。對此,請參考如下示例:

from collections import Counter

cnt = Counter({'a': 4, 'b': 3, 'd': 7, 'c': 5})
cnt1 = Counter({'c': 3, 'd': 2, 'b': 6, 'a': 4})
cnt2 = Counter({'c': 4, 'd': 6, 'b': 2, 'a': 3})

print(cnt > cnt1)
print(cnt > cnt2)

執行效果

False
True

==

== 的左側的 Counter 對象的鍵對應的計數值均等於該符號右側的 Counter 對象中相同的鍵(對於 Counter 中不存在的鍵,其計數值為零)對應的計數值時,比較結果為 True。否則為 False。對此,請參考如下示例:

from collections import Counter

cnt = Counter({'a': 3, 'b': 2, 'd': 6, 'c': 4})
cnt1 = Counter({'c': 3, 'd': 2, 'b': 6, 'a': 4})
cnt2 = Counter({'c': 4, 'd': 6, 'b': 2, 'a': 3})

print(cnt == cnt1)
print(cnt == cnt2)

執行效果

False
True

到此這篇關於Python 中的 Counter 模塊及使用詳解(搞定重復計數)的文章就介紹到這瞭,更多相關Python Counter 模塊內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: