Bucle de ida y vuelta Python


Quiero crear un bucle infinito que cuenta hacia arriba y hacia abajo de 0 a 100 a 0 (y así sucesivamente) y solo se detiene cuando se cumple algún criterio de convergencia dentro del bucle, así que básicamente algo como esto:

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)

¿Hay alguna manera de fusionar los dos bucles for sobre j en uno para que no tenga que escribir el mismo código dentro de los bucles dos veces?

Author: Daniel, 2018-09-05

10 answers

Utilice el método chain de 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)

Como sugiere @Chepner, puedes usar itertools.cycle() para el bucle infinito:

from itertools import cycle, chain

for i in cycle(chain(range(0, 100, 1), range(100, 0, -1))):
    ....
 42
Author: damienfrancois,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-06 06:01:13

Así como las otras respuestas se puede utilizar un poco de matemáticas:

while(True):
    for i in range(200):
        if i > 100:
            i = 200 - i
 17
Author: ncfirth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-05 14:24:58

Aquí hay otra posibilidad:

while notConverged:
    for i in xrange(-100, 101):
        print 100 - abs(i)
 8
Author: twalberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-05 19:52:24

Si tienes un conjunto repetido de código, usa una función para ahorrar espacio y esfuerzo:

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)

Incluso podrías usar un while True

 6
Author: N Chauhan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-05 14:22:18

Si está utilizando Python 3.5+, puede usar el desempaquetado genérico:

for j in (*range(0, 100, 1), *range(100, 0, -1)):

O antes de Python 3.5, puedes usar itertools.chain:

from itertools import chain

...

for j in chain(range(0, 100, 1), range(100, 0, -1)):
 3
Author: blhsing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-05 14:19:21
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
 3
Author: Tanmay jain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-05 16:59:40
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

Esto define un generador, que continuará rindiendo valores durante el tiempo que necesite. Por ejemplo:

>>> 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
 1
Author: mathmandan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-06 05:23:54

Esto es más una respuesta parcial que una respuesta directa a tu pregunta, pero también puedes usar la noción de funciones trigonométricas y su oscilación para imitar un bucle 'ida y vuelta'.

Si tenemos una función cos con una amplitud de 100, desplazada hacia la izquierda y hacia arriba de modo que f(x) = 0 y 0 <= f(x) <= 100, entonces tenemos la fórmula f(x) = 50(cos(x-pi)+1) (la gráfica se puede encontrar aquí. El rango es lo que necesita, y la oscilación se produce por lo que no hay necesidad de negar cualquier valor.

>>> 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

El problema por supuesto viene en que la función no da valores enteros tan fácilmente, por lo que no es tan útil - pero esto puede ser útil para futuros lectores donde las funciones trigonométricas podrían ser útiles para su caso.

 0
Author: TerryA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-06 05:38:42

Tuve un problema similar hace un tiempo donde también quería crear valores en forma de una onda de triángulo infinito, pero quería pasar por encima de algunos valores. Terminé usando un generador (y la función de rango como otros también han estado usando):

def tri_wave(min, max, step=1):
    while True:
        yield from range(min, max, step)
        yield from range(max, min, -1 * step)

Con valores cuidadosamente seleccionados en min, max y step (es decir, uniformemente divisibles),

for value in tri_wave(0, 8, 2):
    print(value, end=", ")

Obtengo el valor mínimo y máximo solo una vez, que era mi objetivo:

...0, 2, 4, 6, 8, 6, 4, 2, 0, 2, 4, 6, 8, 6, 4...

Estaba usando Python 3.6 en ese momento.

 0
Author: Amoork,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-09 06:42:47

Me sentí curioso si es posible implementar este tipo de oscilador triangular sin condiciones y enumeraciones. Bueno, una opción es la siguiente:

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

La idea detrás de esto es tomar 2 ondas de diente de sierra con diferentes períodos y restar una de otra. El resultado será una onda cuadrada con valores en {0, magnitud}. Entonces sólo sustituimos {0, magnitud} con {-1, + 1} respectivamente para obtener valores derivados para nuestra señal de destino.

Veamos el ejemplo con magnitude = 5:

o = oscillator(5)
[next(o) for _ in range(21)]

Esto produce [0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0].

Si se permite abs(), se puede usar por simplicidad. Por ejemplo, el siguiente código da la misma salida que la anterior:

[abs(5 - ((x + 5) % 10)) for x in range(21)]
 0
Author: oblalex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-12 07:57:21