Python 现代开发学习笔记

(十三)用 itertools 组合逐项处理

1. 连接、取段与分批

itertools 提供现成的迭代工具。先看三种已经能用循环展开的动作:

# 标准库中导入迭代工具;它们返回的结果可以继续交给下一段遍历。
from itertools import batched, chain, islice

# chain 先读完第一个来源,再继续第二个来源。
print(list(chain([20, 35], [45])))
# islice 从迭代器当前位置向前读取,取出下标 1、2 对应的项。
reader = iter([10, 20, 35, 45])
print(list(islice(reader, 1, 3)))
print(list(reader))
# batched 是 3.12 提供的工具,每批形成一个元组,末批保留剩余项。
print(list(batched([20, 35, 45, 10, 15], 2)))

输出:

[20, 35, 45]
[20, 35]
[45]
[(20, 35), (45, 10), (15,)]

islice 取到第三项后停下,原来的 reader 已经消耗前三项,最后留下 45。它向前读取,不支持列表那样的负下标和倒着切片。batched(..., 2) 每次从上游取最多两项,适合分批送交后续处理;本笔记使用 3.12 的接口。itertools 工具

2. groupby 按相邻键分组

统计同名书籍时,第二章的字典会把所有同名记录归在一起;groupby 则在键改变时开始新组:

# groupby 连续读取相邻的相同键;不是先把所有同名项自动收拢。
from itertools import groupby

titles = ["A", "A", "B", "A"]
for title, group in groupby(titles):
    print(title, len(list(group)))

print("排序后")
for title, group in groupby(sorted(titles)):
    print(title, len(list(group)))

排序前是 A 2、B 1、A 1,排序后是 A 3、B 1。每个 group 与外层分组迭代器共享读取来源,代码在进入下一组前就把当前组读完。把尚未消费的 group 留到外层循环结束后再读取,来源已经前进,拿不到当时那一整组。

相邻分组的读头与当前组消费

需要全局计数时,可以继续用字典或后面常用工具中的 Counter。需要处理连续片段,例如相邻重复记录或一段相同状态时,groupby 的分组方式正好对应数据的顺序。

笔记正文与全部题解 · Ctrl / ⌘ K