Python 的 collections:别再用字典手写计数和分组
Python 的 collections:别再用字典手写计数和分组
统计词频、按类别分组,是写 Python 时最常遇到的两件事。顺手写法是先建一个空字典,再写一圈 if key in d 判断:
counts = {}
for word in words:
if word in counts:
counts[word] += 1
else:
counts[word] = 1
五六行代码只干了一件事——计数,而且每个要计数的脚本都得重写一遍。字典本身没错,错的是把“缺 key 时怎么办”这件事一次次交给手写判断。collections 里的现成类型,就是为这类重复劳动准备的。
第一个是 Counter,专做计数。上面那段循环可以缩成一行:
from collections import Counter
counts = Counter(words)
print(counts.most_common(3)) # 出现最多的 3 个
Counter 本质还是字典,counts[word] 照常用;没出现过的 key 读出来是 0 而不是抛 KeyError,所以 counts[word] += 1 不用先判断存在。两个 Counter 还能直接相加、相减,合并两份统计结果不用再写循环。想取 Top N,most_common(n) 一步到位,比先排序再切片省事,也少一次写错排序方向的机会。
第二个是 defaultdict,专做分组。按首字母把单词分组,手写字典要先判断 key 在不在:
from collections import defaultdict
groups = defaultdict(list)
for word in words:
groups[word[0]].append(word)
defaultdict(list) 的意思是:访问不存在的 key 时,自动先放一个空列表进去。于是 groups["a"].append(word) 不管 "a" 出现没出现过都能直接写,判断逻辑被收进了类型本身。分组的值也可以是 set 去重、是 int 做累加,工厂函数换一个,整段分组代码不用改结构。记住一点:defaultdict 只在访问时自动建 key,in 判断和 .get() 不会触发它,读之前先想清楚要不要新建。
第三个顺手的是 deque,专做两端操作。列表在尾部追加很快,但在头部插入或弹出要把后面所有元素挪一位,数据量一大就慢下来:
from collections import deque
recent = deque(maxlen=5)
for event in events:
recent.append(event) # 超出 5 条自动丢掉最旧的
deque 两端追加和弹出都是 O(1),appendleft、popleft 随手可用;maxlen 还能顺手做一个固定长度的“最近 N 条”窗口,满了自动丢最旧的,不用自己维护下标。需要随机按下标访问、频繁切片时还是用列表,deque 的长处在两端,不在中间。
最后记住分工:计数找 Counter,分组找 defaultdict,两端进出找 deque。它们都不是新语法,只是把“缺 key 怎么办”“头部操作慢怎么办”这类重复判断收进标准库。字典继续用在它最擅长的地方——明确的 key 到 value 映射;一发现自己又在写 if key in d,就停下来想一想,collections 里是不是已经有人替你写好了。
- 点赞
- 收藏
- 关注作者
评论(0)