Python 产量可以产生多个连续的发电机吗?
这里有两个函数可以将iterable项拆分为子列表。我相信这类任务已经被编程过很多次了。我使用它们来解析由Python 产量可以产生多个连续的发电机吗?,python,iterator,generator,yield,Python,Iterator,Generator,Yield,这里有两个函数可以将iterable项拆分为子列表。我相信这类任务已经被编程过很多次了。我使用它们来解析由repr行组成的日志文件,如('result','case',123,4.56)和('dump',…)等等 我想更改这些,以便它们将生成迭代器而不是列表。因为这个列表可能会越来越大,但我可以根据前几项决定接受它或跳过它。此外,如果iter版本可用,我想嵌套它们,但是使用这些列表版本会因为复制部件而浪费一些内存 但是从一个可移植的源中获得多个生成器对我来说并不容易,所以我请求帮助。如果可能的话
repr
行组成的日志文件,如('result','case',123,4.56)和('dump',…)等等
我想更改这些,以便它们将生成迭代器而不是列表。因为这个列表可能会越来越大,但我可以根据前几项决定接受它或跳过它。此外,如果iter版本可用,我想嵌套它们,但是使用这些列表版本会因为复制部件而浪费一些内存
但是从一个可移植的源中获得多个生成器对我来说并不容易,所以我请求帮助。如果可能的话,我希望避免引入新的课程
另外,如果你知道这个问题的更好的标题,请告诉我
谢谢大家!
def cleave_by_mark (stream, key_fn, end_with_mark=False):
'''[f f t][t][f f] (true) [f f][t][t f f](false)'''
buf = []
for item in stream:
if key_fn(item):
if end_with_mark: buf.append(item)
if buf: yield buf
buf = []
if end_with_mark: continue
buf.append(item)
if buf: yield buf
def cleave_by_change (stream, key_fn):
'''[1 1 1][2 2][3][2 2 2 2]'''
prev = None
buf = []
for item in stream:
iden = key_fn(item)
if prev is None: prev = iden
if prev != iden:
yield buf
buf = []
prev = iden
buf.append(item)
if buf: yield buf
编辑:我自己的答案 多亏了大家的回答,我可以写下我想要的!当然,对于“cleve_for_change”函数,我也可以使用
itertools.groupby
def cleave_by_mark (stream, key_fn, end_with_mark=False):
hand = []
def gen ():
key = key_fn(hand[0])
yield hand.pop(0)
while 1:
if end_with_mark and key: break
hand.append(stream.next())
key = key_fn(hand[0])
if (not end_with_mark) and key: break
yield hand.pop(0)
while 1:
# allow StopIteration in the main loop
if not hand: hand.append(stream.next())
yield gen()
for cl in cleave_by_mark (iter((1,0,0,1,1,0)), lambda x:x):
print list(cl), # start with 1
# -> [1, 0, 0] [1] [1, 0]
for cl in cleave_by_mark (iter((0,1,0,0,1,1,0)), lambda x:x):
print list(cl),
# -> [0] [1, 0, 0] [1] [1, 0]
for cl in cleave_by_mark (iter((1,0,0,1,1,0)), lambda x:x, True):
print list(cl), # end with 1
# -> [1] [0, 0, 1] [1] [0]
for cl in cleave_by_mark (iter((0,1,0,0,1,1,0)), lambda x:x, True):
print list(cl),
# -> [0, 1] [0, 0, 1] [1] [0]
/
注意事项:如果有人要使用这些,请务必按照安德鲁指出的那样,在每一级排放发电机的废气。因为否则,外部生成器屈服循环将从内部生成器左侧的右侧重新启动,而不是从下一个“块”开始的位置重新启动
对于第二个函数,您可以使用
itertools.groupby
相当轻松地完成这一任务
下面是一个替代实现,它现在生成生成器而不是列表:
from itertools import groupby
def cleave_by_change2(stream, key_fn):
return (group for key, group in groupby(stream, key_fn))
这就是它的实际作用(一路上自由打印,所以你可以看到发生了什么):
这将产生:
<generator object <genexpr> at 0x7f17c7727e60>
<itertools._grouper object at 0x7f17c77247d0>
[1, 1, 1]
<itertools._grouper object at 0x7f17c7724850>
[2, 2]
<itertools._grouper object at 0x7f17c77247d0>
[3]
<itertools._grouper object at 0x7f17c7724850>
[2, 2, 2, 2]
[1, 1, 1]
[2, 2]
[3]
[2, 2, 2, 2]
亚当的答案很好。这只是为了防止你好奇如何用手来做:
def cleave_by_change(stream):
def generator():
head = stream[0]
while stream and stream[0] == head:
yield stream.pop(0)
while stream:
yield generator()
for g in cleave_by_change([1,1,1,2,2,3,2,2,2,2]):
print list(g)
其中:
[1, 1, 1]
[2, 2]
[3]
[2, 2, 2, 2]
(以前的版本需要一个hack,或者在python 3中,非本地
,因为我在generator()
中分配了stream
,这使得(第二个变量也被称为)流
本地默认为generator()
请注意,这种方法是危险的——如果您不“消耗”返回的生成器,那么您将得到越来越多的生成器,因为流不会变得更小。我实现了我所描述的:
如果您希望在返回列表之前拒绝该列表,甚至
通过为将要生成的函数提供筛选器参数来生成
可能的当此筛选器拒绝列表前缀时,函数将
扔掉当前输出列表并跳过附加到输出列表
直到下一组开始
如果您希望在返回或甚至生成列表之前拒绝列表,请为函数提供一个可能的筛选器参数。当此筛选器拒绝列表前缀时,函数将丢弃当前输出列表,并在启动下一组之前跳过附加到输出列表。无需此mutable
hack。只需改变流
,而不是重新分配它。提示:stream.pop(0)
<generator object <genexpr> at 0x7f17c7727e60>
<itertools._grouper object at 0x7f17c77247d0>
[1, 1, 1]
<itertools._grouper object at 0x7f17c7724850>
[2, 2]
<itertools._grouper object at 0x7f17c77247d0>
[3]
<itertools._grouper object at 0x7f17c7724850>
[2, 2, 2, 2]
def cleave_by_change(stream):
def generator():
head = stream[0]
while stream and stream[0] == head:
yield stream.pop(0)
while stream:
yield generator()
for g in cleave_by_change([1,1,1,2,2,3,2,2,2,2]):
print list(g)
[1, 1, 1]
[2, 2]
[3]
[2, 2, 2, 2]
def cleave_by_change (stream, key_fn, filter=None):
'''[1 1 1][2 2][3][2 2 2 2]'''
S = object()
skip = False
prev = S
buf = []
for item in stream:
iden = key_fn(item)
if prev is S:
prev = iden
if prev != iden:
if not skip:
yield buf
buf = []
prev = iden
skip = False
if not skip and filter is not None:
skip = not filter(item)
if not skip:
buf.append(item)
if buf: yield buf
print list(cleave_by_change([1, 1, 1, 2, 2, 3, 2, 2, 2, 2], lambda a: a, lambda i: i != 2))
# => [[1, 1, 1], [3]]
print list(cleave_by_change([1, 1, 1, 2, 2, 3, 2, 2, 2, 2], lambda a: a, lambda i: i == 2))
# => [[2, 2], [2, 2, 2, 2]]