跳到主要内容

collections

问题

collections 模块有哪些常用数据结构?defaultdict、Counter、deque、namedtuple 怎么用?

答案

defaultdict

from collections import defaultdict

# 普通 dict 访问不存在的 key 会报 KeyError
# defaultdict 会自动创建默认值
word_count = defaultdict(int) # 默认值 0
for word in ["apple", "banana", "apple"]:
word_count[word] += 1
# {'apple': 2, 'banana': 1}

# 分组
groups = defaultdict(list)
for name, dept in [("Alice", "eng"), ("Bob", "eng"), ("Charlie", "pm")]:
groups[dept].append(name)
# {'eng': ['Alice', 'Bob'], 'pm': ['Charlie']}

Counter

from collections import Counter

# 计数
c = Counter("abracadabra")
# Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})

c.most_common(3) # [('a', 5), ('b', 2), ('r', 2)]
c["a"] # 5
c["z"] # 0(不存在返回 0,不报错)

# Counter 运算
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)
c1 + c2 # Counter({'a': 4, 'b': 3})
c1 - c2 # Counter({'a': 2})

deque(双端队列)

from collections import deque

# 两端 O(1) 操作(list 左端操作是 O(n))
dq = deque([1, 2, 3])
dq.appendleft(0) # deque([0, 1, 2, 3])
dq.popleft() # 0

# 固定长度 → 自动丢弃旧元素
recent = deque(maxlen=3)
for i in range(5):
recent.append(i)
print(recent) # deque([2, 3, 4])

# 旋转
dq = deque([1, 2, 3, 4])
dq.rotate(1) # deque([4, 1, 2, 3])

namedtuple

from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
p = Point(1, 2)
print(p.x, p.y) # 1 2
print(p[0]) # 1(支持索引)
x, y = p # 支持解构

# 不可变,可作为 dict key
# 比 class 更轻量,比 tuple 更可读

OrderedDict

from collections import OrderedDict

# Python 3.7+ dict 已保序,OrderedDict 额外支持:
od = OrderedDict([("a", 1), ("b", 2), ("c", 3)])
od.move_to_end("a") # 移到末尾
od.move_to_end("c", last=False) # 移到开头
# 比较顺序:OrderedDict 的 == 考虑顺序,dict 不考虑

常见面试问题

Q1: defaultdict 和普通 dict 的 setdefault 区别?

答案

功能类似,但 defaultdict 更高效、更简洁:

# setdefault:每次调用都要传默认值
d = {}
d.setdefault("key", []).append(1)

# defaultdict:定义一次默认工厂
d = defaultdict(list)
d["key"].append(1) # 更简洁

Q2: deque 和 list 的区别?什么时候用 deque?

答案

操作listdeque
右端添加/删除O(1)O(1)
左端添加/删除O(n)O(1)
随机访问O(1)O(n)
内存连续数组双向链表块

需要频繁在两端操作时用 deque(如队列、滑动窗口)。

相关链接