关于如何实际使用Python的itertools.groupby()函数,我还没有找到一个可以理解的解释。我想做的是:
取一个列表——在本例中是一个对象化lxml元素的子元素 根据某些标准将其分成几组 然后分别遍历这些组。
我已经查看了文档,但我很难将它们应用到简单的数字列表之外。
那么,如何使用itertools.groupby()呢?还有其他我应该使用的技巧吗?提供良好的“先决条件”阅读的指针也将受到赞赏。
关于如何实际使用Python的itertools.groupby()函数,我还没有找到一个可以理解的解释。我想做的是:
取一个列表——在本例中是一个对象化lxml元素的子元素 根据某些标准将其分成几组 然后分别遍历这些组。
我已经查看了文档,但我很难将它们应用到简单的数字列表之外。
那么,如何使用itertools.groupby()呢?还有其他我应该使用的技巧吗?提供良好的“先决条件”阅读的指针也将受到赞赏。
当前回答
我如何使用Python的itertools.groupby()?
您可以使用groupby来对迭代进行分组。你给groupby一个可迭代对象,和一个可选的键函数/可调用对象,用来检查从可迭代对象中取出的项,它返回一个迭代器,给出一个由可调用键的结果和另一个可迭代对象中的实际项组成的二元组。来自帮助:
groupby(iterable[, keyfunc]) -> create an iterator which returns
(key, sub-iterator) grouped by each value of key(value).
下面是groupby使用协程按计数分组的例子,它使用一个键可调用对象(在本例中是corroutine .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])]
其他回答
重要提示:您必须首先对数据进行排序。
我没有理解的部分是在例子结构中
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 + ".")
这将给你输出:
动物:熊和鸭。 植物:仙人掌。 交通工具:快艇、校车。
我遇到的一个有用的例子可能会有帮助:
from itertools import groupby
#user input
myinput = input()
#creating empty list to store output
myoutput = []
for k,g in groupby(myinput):
myoutput.append((len(list(g)),int(k)))
print(*myoutput)
示例输入:14445221
样本输出:(1,1)(3,4)(1,5)(2,2)(1,1)
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方法实际上只是遍历一个列表,每当键改变时,它就创建一个新组。
from random import randint
from itertools import groupby
l = [randint(1, 3) for _ in range(20)]
d = {}
for k, g in groupby(l, lambda x: x):
if not d.get(k, None):
d[k] = list(g)
else:
d[k] = d[k] + list(g)
上面的代码展示了如何使用groupby根据提供的lambda函数/键对列表进行分组。唯一的问题是输出没有合并,这可以使用字典轻松解决。
例子:
l = [2, 1, 2, 3, 1, 3, 2, 1, 3, 3, 1, 3, 2, 3, 1, 2, 1, 3, 2, 3]
应用groupby后,结果将是:
for k, g in groupby(l, lambda x:x):
print(k, list(g))
2 [2]
1 [1]
2 [2]
3 [3]
1 [1]
3 [3]
2 [2]
1 [1]
3 [3, 3]
1 [1]
3 [3]
2 [2]
3 [3]
1 [1]
2 [2]
1 [1]
3 [3]
2 [2]
3 [3]
一旦字典被使用如下所示的结果可以很容易地迭代:
{2: [2, 2, 2, 2, 2, 2], 1: [1, 1, 1, 1, 1, 1], 3: [3, 3, 3, 3, 3, 3, 3, 3]}
警告:
语法列表(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功能,同时避免那些讨厌的(对于小数据)迭代器。