Подтвердить что ты не робот

Циркулярный итератор в Python

Мне нужно повторять циклический список, возможно, много раз, каждый раз, начиная с последнего посещенного элемента.

Вариант использования - пул соединений. Клиент запрашивает соединение, итератор проверяет, доступно ли указанное соединение, и возвращает его, в противном случае цикл пока не найдет тот, который доступен.

Есть ли простой способ сделать это в Python?

4b9b3361

Ответ 1

Используйте itertools.cycle, что его точное назначение:

from itertools import cycle

lst = ['a', 'b', 'c']

pool = cycle(lst)

for item in pool:
    print item,

Вывод:

a b c a b c ...

(Циклы навсегда, очевидно)


Чтобы вручную увеличить итератор и вытащить из него значения один за другим, просто вызовите next(pool):

>>> next(pool)
'a'
>>> next(pool)
'b'

Ответ 2

Правильный ответ - использовать itertools.cycle. Но предположим, что библиотечная функция не существует. Как вы его реализуете?

Используйте генератор :

def circular():
    while True:
        for connection in ['a', 'b', 'c']:
            yield connection

Затем вы можете использовать оператор for для бесконечного итерации или вы можете вызвать next(), чтобы получить одно следующее значение от итератора генератора:

connections = circular()
next(connections) # 'a'
next(connections) # 'b'
next(connections) # 'c'
next(connections) # 'a'
next(connections) # 'b'
next(connections) # 'c'
next(connections) # 'a'
#....

Ответ 3

Или вы можете сделать вот так:

conn = ['a', 'b', 'c', 'c', 'e', 'f']
conn_len = len(conn)
index = 0
while True:
    print(conn[index])
    index = (index + 1) % conn_len

печатает a b c d e f a b c... навсегда

Ответ 4

вы можете выполнить это с помощью цикла append(pop()):

l = ['a','b','c','d']
while 1:
    print l[0]
    l.append(l.pop(0))

или for i in range():

l = ['a','b','c','d']
ll = len(l)
while 1:
    for i in range(ll):
       print l[i]

или просто:

l = ['a','b','c','d']

while 1:
    for i in l:
       print i

все из которых печатаются:

>>>
a
b
c
d
a
b
c
d
...etc.

из трех я был бы склонен к подходу append (pop()) в качестве функции

servers = ['a','b','c','d']

def rotate_servers(servers):
    servers.append(servers.pop(0))
    return servers

while 1:
    servers = rotate_servers(servers)
    print servers[0]

Ответ 5

Если вы хотите выполнить цикл n раз, используйте рецепт ncycles itertools:

from itertools import chain, repeat


def ncycles(iterable, n):
    "Returns the sequence elements n times"
    return chain.from_iterable(repeat(tuple(iterable), n))


list(ncycles(["a", "b", "c"], 3))
# ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']

Ответ 6

Вам нужен пользовательский итератор - я буду адаптировать итератор из этого ответа.

from itertools import cycle

class ConnectionPool():
    def __init__(self, ...):
        # whatever is appropriate here to initilize
        # your data
        self.pool = cycle([blah, blah, etc])
    def __iter__(self):
        return self
    def __next__(self):
        for connection in self.pool:
            if connection.is_available:  # or however you spell it
                return connection

Ответ 7

Здесь другая альтернатива, может быть, не так питонна.

my_list = [1, 2, 3, 4]

for i in range(10):
    print my_list[i % len(my_list)]

Можно управлять аргументом диапазона для циклической итерации 5 раз, например:

for i in range(len(my_list) * 5):
    print my_list[i % len(my_list)]