Может ли yield создать несколько последовательных генераторов?

Вот две функции, которые разбивают итерируемые элементы на подсписки. Я полагаю, что этот тип задач запрограммирован многими Я использую их для разбора лог-файлов, состоящих из 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

редактировать: мой собственный ответ

Спасибо всем за ответ, Я мог написать то, что я просил! Конечно, что касается функции «cleave_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]

/

def cleave_by_change (stream, key_fn):
    '''[1 1 1][2 2][3][2 2 2 2]'''
    hand = []
    def gen ():
        headkey = key_fn(hand[0])
        yield hand.pop(0)
        while 1:
            hand.append(stream.next())
            key = key_fn(hand[0])
            if key != headkey: 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_change (iter((1,1,1,2,2,2,3,2)), lambda x:x):
    print list(cl),
# -> [1, 1, 1] [2, 2, 2] [3] [2]

ВНИМАНИЕ:Если кто-то собирается их использовать, обязательно исчерпайте генераторына каждом уровне, как указал Эндрю. Потому что в противном случае внешний цикл генерации генератора перезапустится там, где оставил внутренний генератор, а не там, где начинается следующий «блок».

stream = itertools.product('abc','1234', 'ABCD')
for a in iters.cleave_by_change(stream, lambda x:x[0]):
    for b in iters.cleave_by_change(a, lambda x:x[1]):
        print b.next()
        for sink in b: pass
    for sink in a: pass

('a', '1', 'A')
('b', '1', 'A')
('c', '1', 'A')
13
задан h2kyeong 25 May 2012 в 07:08
поделиться