Python groupby 为什么会出现两个同名分组?

举报
yd_239549656 发表于 2026/10/31 08:52:13 2026/10/31
【摘要】 用同一个部门名单样例,对比相邻分组、先排序再分组和字典聚合,避免把 itertools.groupby 当成全局合并。

一份名单里,“研发”出现了两次。直接使用 itertools.groupby,为什么也会得到两个“研发”分组?先看一个可直接运行的样例。

1. 同名分组出现两次

from itertools import groupby

rows = [("研发", "小王"), ("产品", "小李"), ("研发", "小周")]

for team, members in groupby(rows, key=lambda row: row[0]):
    print(team, [name for _, name in members])

实际结果是:

研发 ['小王']
产品 ['小李']
研发 ['小周']

groupby 按相邻元素的键变化划分组。名单从“研发”变为“产品”,再变回“研发”,所以出现三组。后面的同名键不会自动并回前面的组。Python 官方 itertools 文档对这个行为有明确说明。

如果需要表示输入中连续的片段,这个结果就是需要的结果,不必排序。

2. 想按部门合并时,先让同名部门相邻

在接着上例执行时,可以对同一个键排序:

ordered = sorted(rows, key=lambda row: row[0])

for team, members in groupby(ordered, key=lambda row: row[0]):
    print(team, [name for _, name in members])

本样例得到:

产品 ['小李']
研发 ['小王', '小周']

这里使用 sorted 返回新的列表,原始 rows 的顺序保持不变。排序键与分组键一致,才符合这段代码“按部门合并”的目的。不要把例子中的中文排序顺序当成业务规定;有自定义展示顺序时,应明确写出排序规则。

groupby 返回的组本身是迭代器。若准备稍后再处理某一组,应在当前轮用 list(members) 保存它,不要先收集组迭代器,最后才统一消费。

3. 不想为了聚合排序,可以直接用字典

如果目标只是按部门收集成员,下面的写法更直接:

from collections import defaultdict

groups = defaultdict(list)
for team, name in rows:
    groups[team].append(name)

print(dict(groups))

本样例得到:

{'研发': ['小王', '小周'], '产品': ['小李']}

这一版按原始输入顺序向各部门追加成员,但会把成员保存在列表里。数据很大时,需要考虑保存完整分组的内存成本;本文没有做性能或内存基准测试。

4. 先确认需求,再选写法

要保留连续片段,就直接使用 groupby;要把同键记录收在一起,可以先按同一个键排序,也可以用字典累计。不要仅凭函数名判断两种写法等价。

本次教学数据为独立构造的名单,不来自真实人员记录。在本机 Python 3.9.6 中,检查了相邻分组的键与数量、排序后的合并、字典聚合、原始输入保持不变、空输入和相邻重复,共七项断言。

官方参考:docs.python.org/3/library/itertools.html#itertools.groupby。

本文由 AI 辅助整理,示例已在本机实际执行。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。