5

假设我有一个像这样的生成器函数:

import random
def big_gen():
  i = 0
  group = 'a'
  while group != 'd':
    i += 1
    yield (group, i)
    if random.random() < 0.20:
      group = chr(ord(group) + 1)

示例输出可能是:('a', 1), ('a', 2), ('a', 3), ('a', 4), ('a', 5), ('a', 6), ('a', 7), ('a', 8), ('b', 9), ('c', 10), ('c', 11), ('c', 12) , ('c', 13)

我想把它分成三组:A 组、B 组和 C 组。我希望每个组都有一个生成器。然后我将生成器和组字母传递给子函数。子函数的一个例子:

def printer(group_letter, generator):
  print "These numbers are in group %s:" % group_letter
  for num in generator:
    print "\t%s" % num

所需的输出将是:

These numbers are in group a:
1
2
3
4
5
6
7
8
These numbers are in group b:
9
These numbers are in group c:
10
11
12
13

如何在不更改 big_gen() 或 printer() 的情况下做到这一点,并避免一次将整个组存储在内存中?(在现实生活中,群体很大

4

2 回答 2

8

当然,这可以满足您的要求:

import itertools
import operator

def main():
  for let, gen in itertools.groupby(big_gen(), key=operator.itemgetter(0)):
    secgen = itertools.imap(operator.itemgetter(1), gen)
    printer(let, secgen)

groupby在这里完成大部分工作 -key=只是告诉它要分组的字段。

生成的生成器需要包装在 an 中imap,因为您已指定printer签名以对数字进行迭代,而从本质上讲,groupby它返回与其输入相同的项目的迭代器——这里,2 项目元组带有 a字母后跟一个数字 - 但这与您的问题标题并不完全相关。

该标题的答案是,是的,Python 函数可以完美地完成您想要的工作——itertools.groupby事实上正是这样做的。我建议仔细研究itertools模块,它是一个非常有用的工具(并且也提供了出色的性能)。

于 2009-08-01T01:39:01.817 回答
0

你这里有一个小问题。您希望 print() 的函数为每个组获取一个生成器,但实际上您拥有相同的生成器来生成所有组。如我所见,您有两个选择:

1) 将 big_gen() 更改为产量生成器:

import random
def big_gen():
  i = 0
  group = 'a'
  while group != 'd':
    def gen():
        i += 1
        yield i
        if random.random() < 0.20:
            group = chr(ord(group) + 1)
    yield group, gen

 from itertools import imap
 imap(lambda a: printer(*a), big_gen())

2)更改打印机()以保持状态并在组更改时通知(保持您原来的 big_gen() 函数):

def printer(generator):
  group = None
  for grp, num in generator:
    if grp != group:
        print "These numbers are in group %s:" % grp
        group = grp
    print "\t%s" % num
于 2009-08-01T00:40:26.543 回答