Преобразовать питон `цикл` в` список` - PullRequest
0 голосов
/ 17 сентября 2018

Есть ли способ преобразовать cycle из itertools в list? Применение list(my_cycle) останавливает мой компьютер.

Я хотел бы периодически бесконечно переключаться между коллекциями объектов. Они хранятся в цикле. Если один из моих объектов станет «неактивным», я бы хотел удалить его из цикла. Я решил это с помощью другого списка с неактивными объектами, но это выглядит как плохой обходной путь.

Ответы [ 2 ]

0 голосов
/ 17 сентября 2018

Если ваш набор всех объектов (активных и неактивных) никогда не меняется, и особенно если переходы между активным и неактивным состоянием являются общими, общее количество объектов не является возмутительным или набор неактивных объектов обычно не охватывает большинствоиз общего набора, cycle все равно будет работать довольно хорошо, сохраняя set неактивных объектов вокруг и отфильтровывая в настоящее время неактивные объекты "живыми":

from itertools import cycle, filterfalse

allobjects = [...]
numuniqueobjects = len(set(allobjects))
inactiveobjects = set()

# Each time we request an item, filterfalse pulls items from the cycle
# until we find one that isn't in our inactive set
for object in filterfalse(inactiveobjects.__contains__, cycle(allobjects)):

    # ... do actual stuff with object ...

    # Any objects that should go active again get removed from the set and will be
    # seen again the next time their turn comes up in the original order
    inactiveobjects -= objects_that_should_become_active()

    # Won't see this object again until it's removed from inactiveobjects
    if object.should_go_inactive():
        inactiveobjects.add(object)
        if len(inactiveobjects) == numuniqueobjects:
            # Nothing is active, continuing loop would cause infinite loop
            break

Преимущества этого дизайна в том, что:

  1. Это удешевляет активацию и деактивацию объектов
  2. Сохраняет исходный порядок итерации бесконечно (если объект изначально находился в позиции 4, когда он становится неактивным, он пропускается, икогда он снова становится активным, он появляется снова после позиции 3 и до позиции 5 в следующий раз, когда вы выполните цикл)

Основным недостатком является то, что он добавляет чуть больше накладных расходов к «ничего не меняется»случай, особенно если set из inactiveobjects вырастает до заметной доли от общего числа оbjects;вам все равно придется cycle всех объектов, даже если отфильтровать многих из них.

Если это не подходит для вашего варианта использования, пользовательская версия cycle, построенный на deque в соответствии с предложением wim , вероятно, является лучшим решением общего назначения:

from collections import deque
from collections.abc import Iterator

class mutablecycle(Iterator):
    def __init__(self, it):
        self.objects = deque(it)
        self.objects.reverse() # rotate defaults to equivalent of appendleft(pop())
                               # reverse so next item always at index -1

    def __next__(self):
        self.objects.rotate() # Moves rightmost element to index 0 efficiently
        try:
            return self.objects[0]
        except IndexError:
            raise StopIteration

    def removecurrent(self):
        # Remove last yielded element
        del self.objects[0]

    def remove(self, obj):
         self.objects.remove(obj)

    def add(self, obj, *, tofront=True):
        if tofront:
            # Putting it on right makes it be yielded on next request
            self.objects.append(obj)
        else:
            # Putting it on left makes it appear after all other elements
            self.objects.appendleft(obj)

Использование будет:

mycycle = mutablecycle(allobjects):
for object in mycycle:
    # ... do stuff with object ...

    if object.should_go_inactive():
        mycycle.removecurrent()  # Implicitly removes object currently being iterated
0 голосов
/ 17 сентября 2018

Нет, вы не можете, потому что cycle - это бесконечная последовательность.Ваш компьютер "зависает", потому что Python пытается перебрать бесконечный набор элементов (если вы оставите его достаточно долго, процесс будет исчерпан из памяти и аварийно завершится).

Что вы можете сделать, это собратьзаранее определенное конечное количество элементов в списке:

n = 10  # some fixed size 
results = []
for i in range(n):
    results.append(next(my_cycle))

Не существует общего способа узнать, сколько элементов потребляется, чтобы получить один проход в цикле, потому что объект цикла не предоставляет какого-либо состояния опериод основной итерации, т. е. сколько элементов было повторено до повторения.

Не существует общедоступного способа изменить элементы, возвращаемые из цикла после того, как встретился первый StopIteration из исходного итератора, они все где-то буферизуются в приватной памяти:

>>> L = [0,1,2]
>>> g = itertools.cycle(L)
>>> next(g)
0
>>> L.remove(1)
>>> next(g)
2
>>> next(g)
0
>>> L.remove(2)
>>> next(g)
2

Для циклического изменения последовательности, в качестве альтернативного варианта проектирования, вы можете рассмотреть использование экземпляра collections.deque в качестве структуры данных (эффективен метод rotate).

...