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

我一直无法找到如何真正使用Python的itertools.groupby()函数的可理解的解释。 我想要做的是这样的:

  • 列出一个列表 – 在这种情况下,一个客体lxml元素的孩子
  • 根据一些标准将其分组
  • 然后再分别遍历每个这些组。

我已经回顾了文档和示例 ,但是我试图将它们应用到一个简单的数字列表之外时遇到了麻烦。

那么,如何使用itertools.groupby()呢? 还有另一种技术我应该使用? 指出良好的“先决条件”阅读也将不胜感激。

正如Sebastjan所说, 你首先必须对数据进行排序。 这个很重要。

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

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

这会给你输出:

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

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

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方法实际上只是遍历一个列表,每当关键改变它创建一个新的组。

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

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

会给你一个2元组列表,其中第一个元素是char,第二个元素是重复的数目。

编辑:请注意,这是从SQL GROUP BY语义分离itertools.groupby :itertools没有(一般不能)预先对迭代器进行排序,所以具有相同“密钥”的组不会合并。

另一个例子:

 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中的值分组。 在这种情况下,首先输出一组零,然后是一组零,然后再一组零。

 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] 

警告:

语法列表(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 without sort不起作用。 从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. 

有两组车辆,而只有一组车辆

@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函数将不起作用

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

您可以使用groupby将事物分组进行迭代。 你给groupby一个可迭代的,和一个可选的关键函数/可调用来检查项目,因为他们出来的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])] 

排序和groupby

 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'} 

itertools.groupby是一个分组项目的工具。

从文档中 ,我们收集到更多的信息:

# [k for k, g in groupby('AAAABBBCCDAABBB')] --> ABCDAB

# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D

特征

  • A.将连续的项目组合在一起(类似于unique_justseen配方)
  • 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 >>> 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个大小的块
  • 查找数组中重复元素的索引
  • 团体赔率和平等
  • 分档
  • 按值分组
  • 删除重复元素 ( 请参阅笔记本 )
  • 压缩算法 ( 请参阅笔记本 )
  • 按长度分组字母(按 笔记本 )
  • Anagrams( 看笔记本 )
  • 超过阈值的连续值 ( 请参阅笔记本 )

其中几个例子来自VíctorTerrón的PyCon谈话(英语) (西班牙语) , 黎明的功夫与Itertools 。 对于任何感兴趣的人来说,这里是C编写的源代码 。

我遇到的一个有用的例子可能会有帮助:

 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)