How do I use Python's itertools.groupby()?
对于如何实际使用python的
- 取一个列表-在本例中,对象化
lxml 元素的子元素 - 根据某些标准将其分成若干组
- 然后分别对这些组中的每个组进行迭代。
我已经审阅了文档和示例,但在尝试将它们应用于简单的数字列表之外时遇到了困难。
那么,如何使用
重要提示:您必须先对数据进行排序。
我没有得到的部分是在示例构造中
1 2 3 4 5 | groups = [] uniquekeys = [] for k, g in groupby(data, keyfunc): groups.append(list(g)) # Store group iterator as a list uniquekeys.append(k) |
下面是一个例子,使用更清晰的变量名:
1 2 3 4 5 6 7 8 | 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"" |
这将为您提供输出:
A bear is a animal.
A duck is a animal.A cactus is a plant.
A speed boat is a vehicle.
A school bus is a vehicle.
在本例中,
这里,
在上面的
下面是一个使用相同数据的稍微不同的示例,使用列表理解:
1 2 3 | for key, group in groupby(things, lambda x: x[0]): listOfThings =" and".join([thing[1] for thing in group]) print key +"s: " + listOfThings +"." |
这将为您提供输出:
animals: bear and duck.
plants: cactus.
vehicles: speed boat and school bus.
你能给我们看看你的密码吗?
关于python文档的示例非常简单:
1 2 3 4 5 | groups = [] uniquekeys = [] for k, g in groupby(data, keyfunc): groups.append(list(g)) # Store group iterator as a list uniquekeys.append(k) |
因此,在您的例子中,数据是一个节点列表,keypunc是标准函数的逻辑所在,然后
在调用
Neato与Groupby的一个诀窍是在一行中运行长度编码:
1 | [(c,len(list(cgen))) for c,cgen in groupby(some_string)] |
将为您提供两个元组的列表,其中第一个元素是char,第二个元素是重复次数。
编辑:请注意,这是将
从文档中,我们进一步了解了它可能会做什么:
# [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
特征
- a.将连续项目分组在一起
- b.对一个项目的所有出现项进行分组,给出一个已排序的iterable
- c.指定如何使用键函数对项进行分组
比较
1 2 3 4 | # 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))) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # 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'] |
使用
- 变位词(见笔记本)
- 装箱
- 奇数和偶数分组
- 按值对列表分组
- 删除重复元素
- 查找数组中重复元素的索引
- 将数组拆分为n个大小的块
- 在两个列表之间查找相应的元素
- 压缩算法(参见笔记本电脑)/运行长度编码
- 按长度分组字母,键功能(见笔记本)
- 超过阈值的连续值(请参阅笔记本)
- 在列表或连续项目中查找数字范围(请参阅文档)
- 查找所有相关的最长序列
- 采用符合条件的连续序列(见相关文章)
注:后几个例子来源于V_ctor Terr_n的Pycon(Talk)(西班牙语),"黎明功夫与Itertools"。另请参见用C编写的
响应
1 2 | # OP: Yes, you can use `groupby`, e.g. [do_something(list(g)) for _, g in groupby(lxml_elements, key=criteria_func)] |
另一个例子:
1 2 | for key, igroup in itertools.groupby(xrange(12), lambda x: x // 5): print key, list(igroup) |
结果在
1 2 3 | 0 [0, 1, 2, 3, 4] 1 [5, 6, 7, 8, 9] 2 [10, 11] |
请注意,igroup是一个迭代器(文档称之为子迭代器)。
这有助于对发电机进行分块:
1 2 3 4 5 6 7 8 | 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 2 3 4 | 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]) |
生产:
1 2 3 | 0 [0, 1, 2] 1 [3, 4, 5] 0 [6, 7, 8, 9] |
警告:
语法列表(groupby(…)将无法按预期方式工作。它似乎会破坏内部迭代器对象,因此使用
1 2 | for x in list(groupby(range(10))): print(list(x[1])) |
将产生:
1 2 3 4 5 6 7 8 9 10 | [] [] [] [] [] [] [] [] [] [9] |
相反,在groupby(…)]中尝试[(k,list(g))for k,g for k,或者如果经常使用该语法,
1 2 | def groupbylist(*args, **kwargs): return [(k, list(g)) for k, g in groupby(*args, **kwargs)] |
并且可以访问groupby功能,同时避免这些麻烦的(对于小数据)迭代器。
我想再举一个没有排序的GroupBy不起作用的例子。改编自詹姆斯·苏拉克的例子
1 2 3 4 5 6 7 8 | 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"" |
输出是
1 2 3 4 5 6 7 | 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. |
有两组有车辆,而一组只有一组
@Captsolo,我试过你的例子,但没用。
1 2 | from itertools import groupby [(c,len(list(cs))) for c,cs in groupby('Pedro Manoel')] |
输出:
1 | [('P', 1), ('e', 1), ('d', 1), ('r', 1), ('o', 1), (' ', 1), ('M', 1), ('a', 1), ('n', 1), ('o', 1), ('e', 1), ('l', 1)] |
如你所见,有两个O和两个E,但它们是分开的。这时我意识到您需要对传递给groupby函数的列表进行排序。因此,正确的用法是:
1 2 3 | name = list('Pedro Manoel') name.sort() [(c,len(list(cs))) for c,cs in groupby(name)] |
输出:
1 | [(' ', 1), ('M', 1), ('P', 1), ('a', 1), ('d', 1), ('e', 2), ('l', 1), ('n', 1), ('o', 2), ('r', 1)] |
记住,如果列表没有排序,GroupBy函数将不起作用!
Sorting and groupby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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'} |
How do I use Python's itertools.groupby()?
您可以使用groupby对要迭代的内容进行分组。您给groupby一个iterable和一个可选的key函数/callabable,通过它可以检查从iterable出来的项,它返回一个迭代器,它给出了key callabable结果的两个元组和另一个iterable中的实际项。从帮助:
1 2 | groupby(iterable[, keyfunc]) -> create an iterator which returns (key, sub-iterator) grouped by each value of key(value). |
下面是group by的一个例子,它使用coroutine按计数分组,它使用一个键可调用(在本例中是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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)) |
印刷品
1 | [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])] |
您可以编写自己的groupby函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def groupby(data): kv = {} for k,v in data: if k not in kv: kv[k]=[v] else: kv[k].append(v) return kv Run on ipython: In [10]: data = [('a', 1), ('b',2),('a',2)] In [11]: groupby(data) Out[11]: {'a': [1, 2], 'b': [2]} |
我遇到的一个有用的例子可能会有所帮助:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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)