我如何使用Python的itertools.groupby()?

James Sulak 401 python iteration

我无法找到关于如何实际使用Python itertools.groupby()函数的可理解的解释.我想要做的是这样的:

  • 列出一个列表 - 在这种情况下,是一个客观化lxml元素的孩子
  • 根据某些标准将其划分为不同的组
  • 然后分别迭代这些组中的每一个.

我已经阅读了文档示例,但是我在尝试将它们应用到简单的数字列表之外时遇到了麻烦.

那么,我该如何使用itertools.groupby()?我应该使用另一种技术吗?指向良好的"先决条件"阅读的指针也将受到赞赏.

James Sulak.. 565

重要说明:您必须先对数据进行排序.


我没有得到的部分是在示例构造中

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 + "."

这将为您提供输出:

动物:熊和鸭.
植物:仙人掌.
车辆:快艇和校车.

  • @Julian python docs似乎对大多数东西都很好,但是当涉及到迭代器,生成器和软件时,文档大多使我神秘.Django的文档令人倍感莫名其妙. (3认同)

Seb.. 69

你能告诉我们你的代码吗?

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方法实际上只是迭代一个列表,每当密钥更改它创建一个新组.

  • 所以你读了`keyfunc`,就像"是的,我确切地知道那是什么,因为这个文档很简单."?难以置信! (20认同)

nimish.. 36

使用groupby的neato技巧是在一行中运行长度编码:

[(c,len(list(cgen))) for c,cgen in groupby(some_string)]

将给出一个2元组的列表,其中第一个元素是char,第二个元素是重复的数量.

编辑:请注意,这itertools.groupby与SQL GROUP BY语义分开:itertools不会(通常不能)提前对迭代器进行排序,因此不会合并具有相同"键"的组.


pylang.. 29

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, key=None):
...    for k, g in it.groupby(iterable, key):
...        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
>>> key = lambda x: x.islower()
>>> print_groupby(sorted("bCAaCacAADBbB"), key)
key: 'False'--> group: ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D']
key: 'True'--> group: ['a', 'a', 'b', 'b', 'c']

用途

注:后面的几个例子来自VíctorTerrón的PyCon (谈话) (西班牙语),"Dawn with Itertools的功夫".另请参阅用C编写的groupby源代码.


响应

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


user650654.. 24

另一个例子:

for key, igroup in itertools.groupby(xrange(12), lambda x: x // 5):
    print key, list(igroup)

结果是

0 [0, 1, 2, 3, 4]
1 [5, 6, 7, 8, 9]
2 [10, 11]

请注意,igroup是一个迭代器(文档调用它的子迭代器).

这对于分块生成器很有用:

def chunker(items, chunk_size):
    '''Group items in chunks of chunk_size'''
    for _key, group in itertools.groupby(enumerate(items), lambda x: x[0] // chunk_size):
        yield (g[1] for g in group)

with open('file.txt') as fobj:
    for chunk in chunker(fobj):
        process(chunk)

groupby的另一个例子 - 当键没有排序时.在以下示例中,xx中的项目按yy中的值进行分组.在这种情况下,首先输出一组零,然后输出一组1,然后再输出一组零.

xx = range(10)
yy = [0, 0, 0, 1, 1, 1, 0, 0, 0, 0]
for group in itertools.groupby(iter(xx), lambda x: yy[x]):
    print group[0], list(group[1])

生产:

0 [0, 1, 2]
1 [3, 4, 5]
0 [6, 7, 8, 9]


RussellStewa.. 19

警告:

语法列表(groupby(...))将无法按您的意图运行.它似乎破坏了内部迭代器对象,所以使用

for x in list(groupby(range(10))):
    print(list(x[1]))

将产生:

[]
[]
[]
[]
[]
[]
[]
[]
[]
[9]

相反,列表(groupby(...)),尝试[(k,list(g))为k,g in groupby(...)],或者如果经常使用该语法,

def groupbylist(*args, **kwargs):
    return [(k, list(g)) for k, g in groupby(*args, **kwargs)]

并且可以访问groupby功能,同时避免那些讨厌的(对于小数据)迭代器.

  • 许多答案指的是你必须在groupby之前排序以获得预期结果的绊脚石.我刚刚遇到这个答案,这解释了我以前从未见过的奇怪行为.我之前没有见过,因为只是现在才尝试列出(groupby(范围(10))为@singular说.之前我总是使用"推荐"方法"手动"迭代通过groupby对象而不是让list()构造函数"自动"执行它. (3认同)

octoback.. 9

我想举一个例子,其中没有排序的groupby不起作用.改编自James Sulak的例子

from itertools import groupby

things = [("vehicle", "bear"), ("animal", "duck"), ("animal", "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 " "

输出是

A bear is a vehicle.

A duck is a animal.
A cactus is a animal.

A speed boat is a vehicle.
A school bus is a vehicle.

有两个车辆组,而一个人只能期待一组

  • 您必须首先对数据进行排序,使用您要分组的功能作为键.这在上面的两篇文章中提到,但没有突出显示. (4认同)

pedromanoel.. 7

@CaptSolo,我试过你的例子,但它没有用.

from itertools import groupby 
[(c,len(list(cs))) for c,cs in groupby('Pedro Manoel')]

输出:

[('P', 1), ('e', 1), ('d', 1), ('r', 1), ('o', 1), (' ', 1), ('M', 1), ('a', 1), ('n', 1), ('o', 1), ('e', 1), ('l', 1)]

正如你所看到的,有两个和两个e,但它们分成了不同的组.那时我意识到你需要对传递给groupby函数的列表进行排序.所以,正确的用法是:

name = list('Pedro Manoel')
name.sort()
[(c,len(list(cs))) for c,cs in groupby(name)]

输出:

[(' ', 1), ('M', 1), ('P', 1), ('a', 1), ('d', 1), ('e', 2), ('l', 1), ('n', 1), ('o', 2), ('r', 1)]

只记得,如果列表没有排序,groupby函数将无法正常工作!

  • 实际上它有效.您可能认为此行为已损坏,但在某些情况下它很有用.请参阅此问题的答案以获取示例:http://stackoverflow.com/questions/1553275/how-to-strip-a-list-of-tuple-with-python (7认同)

Aaron Hall.. 5

我如何使用Python的itertools.groupby()?

您可以使用groupby将事物分组以进行迭代.你给groupby一个可迭代的,一个可选的key函数/ callable来检查它们从iterable出来时的项目,然后它返回一个迭代器,它给出了一个可以调用键的结果和实际项目的二元组.另一个可迭代的.从帮助:

groupby(iterable[, keyfunc]) -> create an iterator which returns
(key, sub-iterator) grouped by each value of key(value).

下面是groupby使用协程按计数分组的示例,它使用一个密钥可调用(在这种情况下coroutine.send),只是吐出多次迭代的计数和元素的分组子迭代器:

import itertools


def grouper(iterable, n):
    def coroutine(n):
        yield # queue up coroutine
        for i in itertools.count():
            for j in range(n):
                yield i
    groups = coroutine(n)
    next(groups) # queue up coroutine

    for c, objs in itertools.groupby(iterable, groups.send):
        yield c, list(objs)
    # or instead of materializing a list of objs, just:
    # return itertools.groupby(iterable, groups.send)

list(grouper(range(10), 3))

版画

[(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]


用户甲.. 5

排序和分组

from itertools import groupby

val = [{'name': 'satyajit', 'address': 'btm', 'pin': 560076}, 
       {'name': 'Mukul', 'address': 'Silk board', 'pin': 560078},
       {'name': 'Preetam', 'address': 'btm', 'pin': 560076}]


for pin, list_data in groupby(sorted(val, key=lambda k: k['pin']),lambda x: x['pin']):
...     print pin
...     for rec in list_data:
...             print rec
... 
o/p:

560076
{'name': 'satyajit', 'pin': 560076, 'address': 'btm'}
{'name': 'Preetam', 'pin': 560076, 'address': 'btm'}
560078
{'name': 'Mukul', 'pin': 560078, 'address': 'Silk board'}


提问时间:

查看次数:

224831 次

最近活跃:

7 月,4 周 前