关于如何实际使用Python的itertools.groupby()函数,我还没有找到一个可以理解的解释。我想做的是:
取一个列表——在本例中是一个对象化lxml元素的子元素 根据某些标准将其分成几组 然后分别遍历这些组。
我已经查看了文档,但我很难将它们应用到简单的数字列表之外。
那么,如何使用itertools.groupby()呢?还有其他我应该使用的技巧吗?提供良好的“先决条件”阅读的指针也将受到赞赏。
关于如何实际使用Python的itertools.groupby()函数,我还没有找到一个可以理解的解释。我想做的是:
取一个列表——在本例中是一个对象化lxml元素的子元素 根据某些标准将其分成几组 然后分别遍历这些组。
我已经查看了文档,但我很难将它们应用到简单的数字列表之外。
那么,如何使用itertools.groupby()呢?还有其他我应该使用的技巧吗?提供良好的“先决条件”阅读的指针也将受到赞赏。
当前回答
itertools。Groupby是一个对项目进行分组的工具。
从文档中,我们进一步收集了它可能做的事情:
# [k for k, g in groupby('AAAABBBCCDAABBB')]——> AB CDA B # [list(g) for k, g in groupby('AAAABBBCCD')]——> AAAABBBCC
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']
Uses
Anagrams (see notebook) Binning Group odd and even numbers Group a list by values Remove duplicate elements Find indices of repeated elements in an array Split an array into n-sized chunks Find corresponding elements between two lists Compression algorithm (see notebook)/Run Length Encoding Grouping letters by length, key function (see notebook) Consecutive values over a threshold (see notebook) Find ranges of numbers in a list or continuous items (see docs) Find all related longest sequences Take consecutive sequences that meet a condition (see related post)
注意:后面的几个例子来自Víctor Terrón的PyCon (talk)(西班牙语),“Kung Fu at Dawn with Itertools”。请参见用C语言编写的groupby源代码。
*一个函数,其中所有项都被传递和比较,影响结果。其他具有key函数的对象包括sorted(), max()和min()。
响应
# OP: Yes, you can use `groupby`, e.g.
[do_something(list(g)) for _, g in groupby(lxml_elements, criteria_func)]
其他回答
groupby的一个新技巧是在一行中运行长度编码:
[(c,len(list(cgen))) for c,cgen in groupby(some_string)]
会给你一个二元组列表,其中第一个元素是char,第二个元素是重复的次数。
编辑:注意这是itertools的区别。来自SQL GROUP BY语义的groupby: itertools不会(通常也不能)提前对迭代器排序,因此具有相同“key”的组不会合并。
重要提示:您必须首先对数据进行排序。
我没有理解的部分是在例子结构中
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 + ".")
这将给你输出:
动物:熊和鸭。 植物:仙人掌。 交通工具:快艇、校车。
警告:
语法列表(groupby(…))不会按您想要的方式工作。它似乎破坏了内部迭代器对象,所以使用
for x in list(groupby(range(10))):
print(list(x[1]))
会产生:
[]
[]
[]
[]
[]
[]
[]
[]
[]
[9]
而不是list(groupby(…)),尝试[(k, list(g)) for k,g in groupby(…)],或者如果你经常使用这种语法,
def groupbylist(*args, **kwargs):
return [(k, list(g)) for k, g in groupby(*args, **kwargs)]
并且可以访问groupby功能,同时避免那些讨厌的(对于小数据)迭代器。
我想再举一个例子,说明没有排序的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.
有两组有车辆,而我们只能期待一组
Python文档中的示例非常简单:
groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)
在你的例子中,data是一个节点列表,keyfunc是criteria函数的逻辑所在,然后groupby()对数据进行分组。
在调用groupby之前,必须小心地按照条件对数据进行排序,否则它将不起作用。Groupby方法实际上只是遍历一个列表,每当键改变时,它就创建一个新组。