Задний и четвертый циклы 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)]