Je veux créer une boucle infinie qui compte de haut en bas de 0 à 100 à 0 (et ainsi de suite) et qui ne s'arrête que lorsqu'un critère de convergence à l'intérieur de la boucle est rempli.
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)
Existe-t-il un moyen de fusionner les deux boucles for over j en une seule afin de ne pas avoir à écrire deux fois le même code dans les boucles?
Utilisez la méthode 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)
Comme suggéré par @Chepner, vous pouvez utiliser itertools.cycle()
pour la boucle infinie:
from itertools import cycle, chain
for i in cycle(chain(range(0, 100, 1), range(100, 0, -1))):
....
En plus des autres réponses, vous pouvez utiliser un peu de maths:
while(True):
for i in range(200):
if i > 100:
i = 200 - i
Voici encore une autre possibilité:
while notConverged:
for i in xrange(-100, 101):
print 100 - abs(i)
Si vous avez un ensemble de code répété, utilisez une fonction pour économiser de l'espace et des efforts:
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)
Vous pouvez même utiliser un while True
Si vous utilisez Python 3.5+, vous pouvez utiliser la décompression générique:
for j in (*range(0, 100, 1), *range(100, 0, -1)):
ou avant Python 3.5, vous pouvez utiliser itertools.chain
:
from itertools import chain
...
for j in chain(range(0, 100, 1), range(100, 0, -1)):
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
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
Ceci définit un générateur, qui continuera à générer des valeurs aussi longtemps que nécessaire. Par exemple:
>>> 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
C'est plus une réponse partielle qu'une réponse directe à votre question, mais vous pouvez également utiliser la notion de fonctions trigonométriques et leur oscillation pour imiter une boucle de va-et-vient.
Si nous avons une fonction cos avec une amplitude de 100, décalée vers la gauche et vers le haut de telle sorte que f(x) = 0
et 0 <= f(x) <= 100
, nous avons alors la formule f(x) = 50(cos(x-pi)+1)
(le tracé du graphique peut être trouvé ici . La plage correspond à vos besoins et oscille se produit donc il n'y a pas besoin de nier les valeurs.
>>> 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
Bien entendu, le problème vient du fait que la fonction ne donne pas les valeurs entières si facilement, ce n’est donc pas très utile - mais cela peut être utile pour les futurs lecteurs où les fonctions trigonométriques pourraient être utiles dans leur cas.
J'ai eu un problème similaire il y a un moment où je voulais aussi créer des valeurs sous la forme d'une onde triangulaire infinie, mais je voulais passer par-dessus certaines valeurs. J'ai fini par utiliser un générateur (et la fonction de plage comme d'autres ont également utilisé):
def tri_wave(min, max, step=1):
while True:
yield from range(min, max, step)
yield from range(max, min, -1 * step)
Avec des valeurs soigneusement sélectionnées sur min, max et step (c’est-à-dire divisibles de manière égale),
for value in tri_wave(0, 8, 2):
print(value, end=", ")
Je n’obtiens les valeurs min et max qu’une fois, ce qui était mon objectif:
...0, 2, 4, 6, 8, 6, 4, 2, 0, 2, 4, 6, 8, 6, 4...
J'utilisais Python 3.6 à l'époque.
Je suis devenu curieux de savoir s’il était possible de mettre en œuvre ce type d’oscillateur triangulaire sans conditions ni énumérations. Eh bien, une option est la suivante:
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
L'idée derrière ceci est de prendre 2 vagues en dents de scie avec différentes périodes et de les soustraire les unes des autres. Le résultat sera une onde carrée avec des valeurs de {0, magnitude}. Ensuite, nous substituons simplement {0, magnitude} avec {-1, +1} respectivement pour obtenir des valeurs dérivées pour notre signal cible.
Regardons un exemple avec magnitude = 5
:
o = oscillator(5)
[next(o) for _ in range(21)]
Ceci génère [0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0]
.
Si abs()
est autorisé, il peut être utilisé pour des raisons de simplicité. Par exemple, le code suivant donne le même résultat que ci-dessus:
[abs(5 - ((x + 5) % 10)) for x in range(21)]