关于如何实际使用Python的itertools.groupby()函数,我还没有找到一个可以理解的解释。我想做的是:
取一个列表——在本例中是一个对象化lxml元素的子元素 根据某些标准将其分成几组 然后分别遍历这些组。
我已经查看了文档,但我很难将它们应用到简单的数字列表之外。
那么,如何使用itertools.groupby()呢?还有其他我应该使用的技巧吗?提供良好的“先决条件”阅读的指针也将受到赞赏。
关于如何实际使用Python的itertools.groupby()函数,我还没有找到一个可以理解的解释。我想做的是:
取一个列表——在本例中是一个对象化lxml元素的子元素 根据某些标准将其分成几组 然后分别遍历这些组。
我已经查看了文档,但我很难将它们应用到简单的数字列表之外。
那么,如何使用itertools.groupby()呢?还有其他我应该使用的技巧吗?提供良好的“先决条件”阅读的指针也将受到赞赏。
当前回答
遗憾的是,我不认为使用itertools.groupby()是明智的。要安全使用它太难了,而且只需要几行代码就可以写出一些可以按照预期工作的东西。
def my_group_by(iterable, keyfunc):
"""Because itertools.groupby is tricky to use
The stdlib method requires sorting in advance, and returns iterators not
lists, and those iterators get consumed as you try to use them, throwing
everything off if you try to look at something more than once.
"""
ret = defaultdict(list)
for k in iterable:
ret[keyfunc(k)].append(k)
return dict(ret)
像这样使用它:
def first_letter(x):
return x[0]
my_group_by('four score and seven years ago'.split(), first_letter)
得到
{'f': ['four'], 's': ['score', 'seven'], 'a': ['and', 'ago'], 'y': ['years']}
其他回答
重要提示:您必须首先对数据进行排序。
我没有理解的部分是在例子结构中
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 + ".")
这将给你输出:
动物:熊和鸭。 植物:仙人掌。 交通工具:快艇、校车。
遗憾的是,我不认为使用itertools.groupby()是明智的。要安全使用它太难了,而且只需要几行代码就可以写出一些可以按照预期工作的东西。
def my_group_by(iterable, keyfunc):
"""Because itertools.groupby is tricky to use
The stdlib method requires sorting in advance, and returns iterators not
lists, and those iterators get consumed as you try to use them, throwing
everything off if you try to look at something more than once.
"""
ret = defaultdict(list)
for k in iterable:
ret[keyfunc(k)].append(k)
return dict(ret)
像这样使用它:
def first_letter(x):
return x[0]
my_group_by('four score and seven years ago'.split(), first_letter)
得到
{'f': ['four'], 's': ['score', 'seven'], 'a': ['and', 'ago'], 'y': ['years']}
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)]
另一个例子:
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中的值进行分组。在这种情况下,首先输出一组0,然后是一组1,然后又是一组0。
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]
排序和分组
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'}