Перебор списка или чисел по кругу (циклический обход)
Бывает необходимость в переборе списка (в принципе элементов любой структуры) или последовательности чисел таким образом, чтобы достигнув конца (последнего элемента или предела числового ряда) перебор начинался сначала. Другими словами, речь идет о циклическом обходе.
Условие окончания такого перебора зависит от конкретной программы. Так в событийно-ориентированных очередной элемент может запрашиваться только при определенном событии. При этом количество проходов по структуре никак не лимитируется и не влияет на завершение работы приложения. Однако в других случаях и демонстрационных примерах мы должны решить, когда обход должен завершаться.
Способов циклического перебора немало. Выбор оптимального зависит от программы, условия завершения извлечения элементов, список это или числовая последовательность.
Наиболее очевидный способ - это ввести счетчик. Когда он достигает последнего элемента, следует его обнулять:
colors = ['red', 'green', 'blue', 'orange']
i = 0
while True:
if input() != '': # любое условие окончания цикла
break
print(colors[i])
i += 1
if i == len(colors):
i = 0
for j in range(len(colors)*2): # любое ограничение числа проходов по списку
print(colors[i])
i += 1
if i == len(colors):
i = 0
x = 0
offset = 25
limit = 100
count = 0
while count < 3:
print(x, end=' ')
x += offset
if x > limit:
count += 1
x = 0
Наиболее элегантным способом такого решения является использование операции нахождение остатка вместо условного оператора:
colors = ['red', 'green', 'blue', 'orange']
i = 0
while True:
if input() != '': break
print(colors[i])
i += 1
i %= len(colors)
x = 0
offset = 25
limit = 125
count = 0
for i in range(15):
print(x, end=' ')
x += offset
x %= limit
Здесь, когда находится остаток от деления на максимум, переменной заново присваивается то же самое значение за исключением случая, когда она равна максимуму. В этом случае переменная обнуляется.
В языке программирования Python есть модуль itertools
, а в нем функция cycle
, которая создает бесконечный итератор.
from itertools import cycle
lst = ['a', 'b', 'c', 'd']
for i in cycle(lst):
if input() != '': break
print(i)
В cycle
можно передать объект range
. Например, cycle(range(0, 101, 20))
.
Если объект, возвращаемый cycle()
, передать в функцию enumerate()
, будет возвращен экземпляр класса enumerate
. В нем каждому значению будет сопоставлен индекс. Экземпляры enumerate
связаны со структурами, от которых были созданы. Поэтому если список конечен, enumerate
будет таким же. Но поскольку экземпляр cycle
бесконечен, enumerate
не имеет последнего элемента.
pool = cycle(lst)
epool = enumerate(pool)
for i, item in epool:
print(i, item)
if i == 9: break
Если надо выводить не индекс в enumerate
, а индекс элемента в исходном списке, то также можно воспользоваться операцией нахождения остатка: print(i%len(lst), item)
.
Когда необходимо целое число циклических проходов, можно воспользоваться вложением цикла в цикл:
lst = ['a', 'b', 'c', 'd']
while True:
for i in lst:
print(i, end=' ')
if input() != '': break