python - Pitón de ida y vuelta
loops for-loop (10)
Además de las otras respuestas, puedes usar un poco de matemáticas:
while(True):
for i in range(200):
if i > 100:
i = 200 - i
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 combinar los dos bucles for j sobre uno en uno para que no tenga que escribir el mismo código dentro de los bucles dos veces?
Aquí hay otra posibilidad:
while notConverged:
for i in xrange(-100, 101):
print 100 - abs(i)
Esta es más una respuesta parcial que una respuesta directa a su pregunta, pero también puede usar la noción de funciones trigonométricas y su oscilación para imitar un bucle de ''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)
(el gráfico del gráfico se puede encontrar here . El rango es lo que necesita, y se produce una oscilación, por lo que no es necesario negar ningún 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
Por supuesto, el problema es que la función no proporciona 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.
Hace un tiempo tuve un problema similar en el que también quería crear valores en forma de una onda triangular infinita, pero quería pasar por encima de algunos valores. Terminé usando un generador (y la función de rango como otras 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, divisibles uniformemente),
for value in tri_wave(0, 8, 2):
print(value, end=", ")
Obtengo el valor mínimo y máximo una sola vez, que era mi objetivo:
...0, 2, 4, 6, 8, 6, 4, 2, 0, 2, 4, 6, 8, 6, 4...
Yo estaba usando Python 3.6 en ese momento.
Sentí curiosidad si es posible implementar este tipo de oscilador de triángulo 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}. Luego simplemente 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 el mismo resultado que arriba:
[abs(5 - ((x + 5) % 10)) for x in range(21)]
Si está usando 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)):
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
Utilice el método de 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)
Según lo sugerido por @Chepner, puede 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))):
....
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á produciendo 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
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