Python 用groupby()切分迭代器,通过对每个元素应用key
函数进行求值,groupby()
函数将一个迭代器切分为多个小迭代器。如果后一个元素的key
值等于前一个元素的key
值,会将这两个元素放在同一个分组中;如果与前一个元素的key
值不同,则当前分组结束,将当前元素放到新的分组中。
groupby()
函数的输出是一系列二元组,每个元组包括一个key
值和包含该组元素的迭代器,该迭代器的元素可以通过转换保存为元组,也可以归约为汇总值。这种情况下将不会保留迭代器中的值。
前面介绍了如何计算输入序列的四等分值。
基于旅行原始数据和算出的四等分值,可如下所示对数据进行分组:
group_iter = groupby(
zip(quartile, trip),
key=lambda q_raw: q_raw[0])
for group_key, group_iter in group_iter:
print(group_key, tuple(group_iter))
首先用zip()
函数将四等分值和原始数据组合在一起,返回包含二元组的迭代器,然后用groupby()
函数基于给定的匿名函数按照四等分值对数据进行分组,最后用for
循环检查groupby()
函数的返回结果。整个过程展示了获得键值组以及包含组成员的迭代器的方法。
groupby()
函数的输入中的key
值必须是排序好的,以确保分在一组中的元素是相邻的。
请注意,也可以使用defaultdict(list)
方法创建分组,实现方法如下:
from collections import defaultdict
from typing import Iterable, Callable, Tuple, List, Dict
D_ = TypeVar("D_")
K_ = TypeVar("K_")
def groupby_2(
iterable: Iterable[D_],
key: Callable[[D_], K_]
) -> Iterator[Tuple[K_, Iterator[D_]]]:
groups: Dict[K_, List[D_]] = defaultdict(list)
for item in iterable:
groups[key(item)].append(item)
for g in groups:
yield g, iter(groups[g])
首先创建了一个defaultdict
类,并为每个键值关联一个list
对象。类型标示指出,key()
函数将任意数据类型转化为键值类型K_
,与字典中的键值类型K_
是一致的。
每个数据项通过key()
函数生成键值,数据项本身被追加到该键值对应的defaultdict
类列表中。
完成对所有数据项的分组后,就可以按照每个共同的key
以迭代方式返回每个分组了,这与groupby()
函数的行为类似。由于作为输入的迭代器的排序结果不一定一致,分组结果可能包含相同的元素,但顺序可能不同。
类型标示中,源数据的类型是D_
,返回结果是一个包含D_
型迭代器的迭代器,表明函数没有执行映射操作,输入数据类型与范围对象的类型完全一致。