如何使用itertools.groupby()?

694 投票
15 回答
462776 浏览
提问于 2025-04-11 00:18

我一直找不到一个简单易懂的解释,来说明如何使用Python的itertools.groupby()函数。我想做的事情是:

  • 先拿一个列表——在这个例子中,是一个被对象化的lxml元素的子元素
  • 根据某些标准把它分成几个组
  • 然后再分别遍历这些组。

我看过官方文档,但在尝试应用这些内容时,除了简单的数字列表外,我遇到了困难。

那么,我该如何使用itertools.groupby()呢?有没有其他的技巧我应该使用?如果能推荐一些好的“基础”阅读材料,我也会很感激。

相关问题:

15 个回答

74

Python文档中的例子非常简单明了:

groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
    groups.append(list(g))      # Store group iterator as a list
    uniquekeys.append(k)

在你的情况下,数据是一个节点的列表,keyfunc 是你放置判断条件逻辑的地方,然后 groupby() 就会把数据分组。

你必须小心,在调用 groupby 之前先对数据进行排序,否则它就无法正常工作。groupby 方法实际上只是遍历一个列表,每当关键字变化时,它就会创建一个新的分组。

162

itertools.groupby 是一个用来对项目进行分组的工具。

根据 官方文档,我们可以进一步了解它的功能:

# [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B

# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D

groupby 对象会生成键-组对,其中组是一个生成器。

特点

  • A. 将连续的项目放在一起
  • B. 在给定一个已排序的可迭代对象时,分组所有相同的项目
  • C. 使用一个 键函数 指定如何分组项目 *

比较

# Define a printer for comparing outputs
>>> def print_groupby(iterable, keyfunc=None):
...    for k, g in it.groupby(iterable, keyfunc):
...        print("key: '{}'--> group: {}".format(k, list(g)))
# Feature A: group consecutive occurrences
>>> print_groupby("BCAACACAADBBB")
key: 'B'--> group: ['B']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A', 'A']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A', 'A']
key: 'D'--> group: ['D']
key: 'B'--> group: ['B', 'B', 'B']

# Feature B: group all occurrences
>>> print_groupby(sorted("BCAACACAADBBB"))
key: 'A'--> group: ['A', 'A', 'A', 'A', 'A']
key: 'B'--> group: ['B', 'B', 'B', 'B']
key: 'C'--> group: ['C', 'C', 'C']
key: 'D'--> group: ['D']

# Feature C: group by a key function
>>> # islower = lambda s: s.islower()                      # equivalent
>>> def islower(s):
...     """Return True if a string is lowercase, else False."""   
...     return s.islower()
>>> print_groupby(sorted("bCAaCacAADBbB"), keyfunc=islower)
key: 'False'--> group: ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D']
key: 'True'--> group: ['a', 'a', 'b', 'b', 'c']

用途

注意:后面几个例子来源于 Víctor Terrón 的 PyCon (演讲) (西班牙语),主题是“用 Itertools 的清晨功夫”。还可以查看 groupby 用 C 写的源代码

* 键函数是一个将所有项目传入并进行比较的函数,从而影响结果。其他有键函数的对象包括 sorted()max()min()


回应

# OP: Yes, you can use `groupby`, e.g. 
[do_something(list(g)) for _, g in groupby(lxml_elements, criteria_func)]
867

重要提示:可能需要先对数据进行排序


我不太明白的是,在这个示例构造中

groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
   groups.append(list(g))    # Store group iterator as a list
   uniquekeys.append(k)

k是当前的分组关键字,而g是一个迭代器,你可以用它来遍历由这个分组关键字定义的组。换句话说,groupby迭代器本身返回的是迭代器。

下面是一个更清晰变量名的示例:

from itertools import groupby

things = [("animal", "bear"), ("animal", "duck"), ("plant", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]

for key, group in groupby(things, lambda x: x[0]):
    for thing in group:
        print("A %s is a %s." % (thing[1], key))
    print("")
    

这将给你输出:

熊是一种动物。
鸭子是一种动物。

仙人掌是一种植物。

快艇是一种交通工具。
校车是一种交通工具。

在这个例子中,things是一个元组的列表,每个元组的第一个项目是该元组第二个项目所属的组。

groupby()函数有两个参数:(1) 要分组的数据和 (2) 用于分组的函数。

这里,lambda x: x[0]告诉groupby()使用每个元组的第一个项目作为分组关键字。

在上面的for语句中,groupby返回三个(关键字,组迭代器)对——每个唯一的关键字一次。你可以使用返回的迭代器来遍历该组中的每个单独项目。

这里有一个稍微不同的例子,使用相同的数据,采用列表推导:

for key, group in groupby(things, lambda x: x[0]):
    listOfThings = " and ".join([thing[1] for thing in group])
    print(key + "s:  " + listOfThings + ".")

这将给你输出:

动物:熊和鸭子。
植物:仙人掌。
交通工具:快艇和校车。

撰写回答