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?
答案:
| 操作 | list | deque |
|---|---|---|
| 右端添加/删除 | O(1) | O(1) |
| 左端添加/删除 | O(n) | O(1) |
| 随机访问 | O(1) | O(n) |
| 内存 | 连续数组 | 双向链表块 |
需要频繁在两端操作时用 deque(如队列、滑动窗口)。