Изменить Itertools.cycle()

В настоящее время я использую объект itertools.cycle(), и мне было интересно, можно ли вообще изменить цикл после его создания. Следующее:

my_cycle = itertools.cycle([1,2,3])
print my_cycle.next()
my_cycle.delete()    #function doesn't exist
print my_cycle.next()

будет иметь вывод:

1
3

Есть ли способ добиться этого с помощью itertools? Или, может быть, другой объект? Или мне нужно реализовать свой собственный объект, чтобы сделать это.


person Philip Massey    schedule 26.06.2014    source источник
comment
чего вы пытаетесь достичь?   -  person Padraic Cunningham    schedule 26.06.2014


Ответы (2)


Itertools не предоставляет такой возможности. Вы можете создать его с помощью deque:

from collections import deque

class ModifiableCycle(object):
    def __init__(self, items=()):
        self.deque = deque(items)
    def __iter__(self):
        return self
    def __next__(self):
        if not self.deque:
            raise StopIteration
        item = self.deque.popleft()
        self.deque.append(item)
        return item
    next = __next__
    def delete_next(self):
        self.deque.popleft()
    def delete_prev(self):
        # Deletes the item just returned.
        # I suspect this will be more useful than the other method.
        self.deque.pop()
person user2357112 supports Monica    schedule 26.06.2014
comment
Я не знал о таких! Прохладный! Спасибо. - person Philip Massey; 26.06.2014

Если вы хотите пропустить значение, вы можете просто вызвать next один раз.

Если вы хотите навсегда удалить одно из значений из цикла, по значению вы можете создать генератор.

def skip_matching(gen, value):
    for v in gen:
        if v == value:
            continue
        yield v

Затем вы можете обернуть цикл следующим образом:

>>> a = skip_matching(itertools.cycle([1,2,3]), 2)
>>> a.next()
1
>>> a.next()
3
>>> a.next()
1

Если вы хотите удалить следующее значение по позиции (не удаляя другие совпадающие с ним значения), вы должны знать длину цикла n. Затем вы можете пропустить один и собрать n-1, чтобы создать новый цикл.

c.next()
c = itertools.cycle(c.next() for i in range(n-1))
person otus    schedule 26.06.2014
comment
skip_matching не работает правильно, когда элемент появляется несколько раз в цикле или когда все содержимое цикла удаляется. - person user2357112 supports Monica; 26.06.2014
comment
@ user2357112, да, я упоминаю первое. Что касается последнего, есть ли правильное решение? - person otus; 26.06.2014
comment
Повышение StopIteration кажется мне правильным. - person user2357112 supports Monica; 26.06.2014
comment
@ user2357112, да, возможно, но это невозможно, если вам дан цикл неизвестной длины. Вам снова нужно знать длину. Поэтому использование пользовательского класса, как вы, может быть более разумным вариантом. - person otus; 26.06.2014