Циркулярный итератор в Python
Мне нужно повторять циклический список, возможно, много раз, каждый раз, начиная с последнего посещенного элемента.
Вариант использования - пул соединений. Клиент запрашивает соединение, итератор проверяет, доступно ли указанное соединение, и возвращает его, в противном случае цикл пока не найдет тот, который доступен.
Есть ли простой способ сделать это в Python?
Ответы
Ответ 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)]