Задний и четвертый циклы Python
Я хочу создать бесконечный цикл, который подсчитывает вверх и вниз от 0 до 100 до 0 (и так далее) и останавливается только тогда, когда выполняется некоторый критерий конвергенции внутри цикла, поэтому в основном что-то вроде этого:
for i in range(0, infinity):
for j in range(0, 100, 1):
print(j) # (in my case 100 lines of code)
for j in range(100, 0, -1):
print(j) # (same 100 lines of code as above)
Есть ли способ слить два для циклов над j в один, чтобы я не дважды записывал один и тот же код внутри циклов?
Ответы
Ответ 1
Используйте chain
метод itertools
import itertools
for i in range(0, infinity):
for j in itertools.chain(range(0, 100, 1), range(100, 0, -1)):
print(j) # (in my case 100 lines of code)
Как было предложено @Chepner, вы можете использовать itertools.cycle()
для бесконечного цикла:
from itertools import cycle, chain
for i in cycle(chain(range(0, 100, 1), range(100, 0, -1))):
....
Ответ 2
Как и другие ответы, вы можете использовать немного математики:
while(True):
for i in range(200):
if i > 100:
i = 200 - i
Ответ 3
Здесь еще одна возможность:
while notConverged:
for i in xrange(-100, 101):
print 100 - abs(i)
Ответ 4
Если у вас есть повторяющийся набор кода, используйте функцию для экономии места и усилий:
def function(x, y, x, num_from_for_loop):
# 100 lines of code
while not condition:
for i in range(1, 101):
if condition:
break
function(x, y, z, i)
for i in range(100, 0, -1):
if condition:
break
function(x, y, z, i)
Вы даже можете использовать while True
Ответ 5
Если вы используете Python 3. 5+, вы можете использовать общую распаковку:
for j in (*range(0, 100, 1), *range(100, 0, -1)):
или до Python 3.5, вы можете использовать itertools.chain
:
from itertools import chain
...
for j in chain(range(0, 100, 1), range(100, 0, -1)):
Ответ 6
up = True # since we want to go from 0 to 100 first
while True: #for infinite loop
# For up == True we will print 0-->100 (0,100,1)
# For up == False we will print 100-->0 (100,0,-1)
start,stop,step = (0,100,1) if up else (100,0,-1)
for i in range(start,stop,step):
print(i)
up = not up # if we have just printed from 0-->100 (ie up==True), we want to print 100-->0 next so make up False ie up = not up( True)
# up will help toggle, between 0-->100 and 100-->0
Ответ 7
def up_down(lowest_value, highest_value):
current = lowest_value
delta = 1
while True: # Begin infinite loop
yield current
current += delta
if current <= lowest_value or current >= highest_value:
delta *= -1 # Turn around when either limit is hit
Это определяет генератор, который будет продолжать давать значения столько, сколько вам нужно. Например:
>>> u = up_down(0, 10)
>>> count = 0
>>> for j in u:
print(j) # for demonstration purposes
count += 1 # your other 100 lines of code here
if count >= 25: # your ending condition here
break
0
1
2
3
4
5
6
7
8
9
10
9
8
7
6
5
4
3
2
1
0
1
2
3
4
Ответ 8
Это скорее частичный ответ, чем прямой ответ на ваш вопрос, но вы также можете использовать понятие тригонометрических функций и их колебания для имитации цикла "назад и вперед".
Если у нас есть функция cos с амплитудой 100, сдвинутая влево и вверх так, чтобы f(x) = 0
и 0 <= f(x) <= 100
, тогда мы имеем формулу f(x) = 50(cos(x-pi)+1)
(график графика можно найти здесь. Диапазон - это то, что вам нужно, и происходит колебание, поэтому нет необходимости отрицать любые значения.
>>> from math import cos, pi
>>> f = lambda x: 50*(cos(x-pi)+1)
>>> f(0)
0.0
>>> f(pi/2)
50.0
>>> f(pi)
100.0
>>> f(3*pi/2)
50.0
>>> f(2*pi)
0.0
Разумеется, проблема заключается в том, что функция не дает так легко целочисленных значений, поэтому это не так полезно, но это может быть полезно для будущих читателей, где тригонометрические функции могут быть полезны для их случая.
Ответ 9
Некоторое время назад у меня была аналогичная проблема, когда я также хотел создавать значения в виде бесконечной волны треугольника, но хотел перешагнуть некоторые значения. Я закончил использование генератора (и функция диапазона, как и другие, также использовались):
def tri_wave(min, max, step=1):
while True:
yield from range(min, max, step)
yield from range(max, min, -1 * step)
С тщательно подобранными значениями на min, max и step (т.е. равномерно делимыми),
for value in tri_wave(0, 8, 2):
print(value, end=", ")
Я получаю значение min и max только один раз, что было моей целью:
...0, 2, 4, 6, 8, 6, 4, 2, 0, 2, 4, 6, 8, 6, 4...
В то время я использовал Python 3.6.
Ответ 10
Мне стало любопытно, можно ли реализовать такой тип треугольного генератора без условий и перечислений. Ну, один из вариантов:
def oscillator(magnitude):
i = 0
x = y = -1
double_magnitude = magnitude + magnitude
while True:
yield i
x = (x + 1) * (1 - (x // (double_magnitude - 1))) # instead of (x + 1) % double_magnitude
y = (y + 1) * (1 - (y // (magnitude - 1))) # instead of (y + 1) % magnitude
difference = x - y # difference ∈ {0, magnitude}
derivative = (-1 * (difference > 0) + 1 * (difference == 0))
i += derivative
Идея этого заключается в том, чтобы взять 2 пилообразные волны с разными периодами и вычесть одно из другого. Результатом будет прямоугольная волна со значениями в {0, величина}. Затем мы просто подставляем {0, величину} на {-1, +1}, чтобы получить производные значения для нашего целевого сигнала.
Рассмотрим пример с magnitude = 5
:
o = oscillator(5)
[next(o) for _ in range(21)]
Это выводит [0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0]
.
Если abs()
разрешено, его можно использовать для простоты. Например, следующий код дает тот же результат, что и выше:
[abs(5 - ((x + 5) % 10)) for x in range(21)]