J'y vais probablement de la mauvaise manière, mais je me demandais comment gérer cela en python.
D'abord du code c:
int i;
for(i=0;i<100;i++){
if(i == 50)
i = i + 10;
printf("%i\n", i);
}
Ok donc on ne voit jamais les années 50 ...
Ma question est la suivante: comment puis-je faire quelque chose de similaire en python? Par exemple:
for line in cdata.split('\n'):
if exp.match(line):
#increment the position of the iterator by 5?
pass
print line
Avec mon expérience limitée en python, je n'ai qu'une solution, introduire un compteur et une autre instruction if. rompre la boucle jusqu'à ce que le compteur atteigne 5 après qu'exp.match (ligne) est vraie.
Il doit exister un meilleur moyen de le faire, espérons-le, qui ne nécessite pas l'importation d'un autre module.
Merci d'avance!
Il existe un paquet fantastique en Python appelé itertools
.
Mais avant d’entrer dans ces termes, il serait utile d’expliquer comment le protocole d’itération est implémenté en Python. Lorsque vous souhaitez fournir une itération sur votre conteneur, vous spécifiez la méthode __iter__()
class qui fournit un type iterator . "Comprendre l'instruction 'pour' de Python" est un article de Nice qui décrit le fonctionnement de l'instruction for-in
en Python et fournit une vue d'ensemble de Nice sur le fonctionnement des types d'itérateurs.
Jetez un oeil à ce qui suit:
>>> sequence = [1, 2, 3, 4, 5]
>>> iterator = sequence.__iter__()
>>> iterator.next()
1
>>> iterator.next()
2
>>> for number in iterator:
print number
3
4
5
Revenons maintenant à itertools
. Le paquet contient des fonctions à différentes fins d'itération. Si vous avez besoin de faire un séquençage spécial, c'est le premier endroit à examiner.
En bas, vous trouverez la section Recipes qui contient recettes pour créer un jeu d’outils étendu en utilisant les outils de navigation existants comme blocs de construction.
Et il y a une fonction intéressante qui fait exactement ce dont vous avez besoin:
def consume(iterator, n):
'''Advance the iterator n-steps ahead. If n is none, consume entirely.'''
collections.deque(itertools.islice(iterator, n), maxlen=0)
Voici un exemple rapide et lisible sur son fonctionnement (Python 2.5):
>>> import itertools, collections
>>> def consume(iterator, n):
collections.deque(itertools.islice(iterator, n))
>>> iterator = range(1, 16).__iter__()
>>> for number in iterator:
if (number == 5):
# Disregard 6, 7, 8, 9 (5 doesn't get printed just as well)
consume(iterator, 4)
else:
print number
1
2
3
4
10
11
12
13
14
15
lines = iter(cdata.splitlines())
for line in lines:
if exp.match(line):
#increment the position of the iterator by 5
for _ in itertools.islice(lines, 4):
pass
continue # skip 1+4 lines
print line
Par exemple, si exp
, cdata
sont:
exp = re.compile(r"skip5")
cdata = """
before skip
skip5
1 never see it
2 ditto
3 ..
4 ..
5 after skip
6
"""
Alors la sortie est:
avant de passer 5 après de passer 6
i = 0
while i < 100:
if i == 50:
i += 10
print i
i += 1
Comme @ [Glenn Maynard] l'a souligné dans le commentaire si vous devez effectuer de très grands sauts tels que i + = 100000000, vous devez utiliser une boucle explicite while
au lieu de simplement sauter des étapes d'une boucle for
.
Voici l'exemple qui utilise la boucle explicite while
à la place de islice
:
lines = cdata.splitlines()
i = 0
while i < len(lines):
if exp.match(lines[i]):
#increment the position of the iterator by 5
i += 5
else:
print lines[i]
i += 1
Cet exemple produit le même résultat que l'exemple islice
ci-dessus.
Si vous le faites avec des chiffres, une compréhension de liste peut fonctionner:
for i in [x for x in range(0, 99) if x < 50 and x > 59]:
print i
Faire avancer un itérateur est un peu plus difficile cependant. Si vous ne souhaitez pas utiliser la méthode du compteur, vous pouvez probablement créer votre liste au préalable, probablement en scindant cdata, puis en travaillant sur les index de la ligne correspondante et en supprimant cette ligne et les suivantes. En dehors de cela, vous êtes coincé avec l'approche du compteur qui n'est pas aussi désagréable que vous le prétendez être honnête.
Une autre option est la suivante:
iterator = iter(cdata.split('\n'))
for line in iterator:
if exp.match(line):
for i in range(0, 5):
try:
iterator.next()
except StopIteration:
break
else:
print line
Je ne suis pas tout à fait sûr de suivre votre processus de pensée, mais voici de quoi vous nourrir ..
for i in range(len(cdata.split('\n'))):
if i in range(50,60): continue
line = cdata[i]
if exp.match(line):
#increment the position of the iterator by 5?
pass
print line
Vous ne savez pas vraiment ce que vous cherchez, mais la fourchette (len (..)) devrait vous aider.
Vous pouvez supprimer des valeurs d'un itérateur
def dropvalues(iterator, vals):
for i in xrange(vals): iterator.next()
Maintenant, assurez-vous d’avoir un objet itérateur sur lequel travailler avec lines = iter(cdata.split('\n'))
; et boucle dessus.
pour votre exemple, puisque vous travaillez avec des listes (séquences indexables) et non avec des itérateurs, je vous recommande ce qui suit:
lines = cdata.split("\n")
for line in lines[:50]+lines[60:]:
print line
ce n'est pas le plus efficace car il construit potentiellement 3 nouvelles listes (mais si la partie ignorée est plus grande que la partie traitée, elle pourrait être plus efficace que les autres options), mais elle est assez claire et explicite.
Si vous ne voulez pas utiliser le module itertools, vous pouvez facilement convertir les listes en séquences:
from itertools import chain, islice
for line in chain(islice(lines, None, 50), islice(lines, 60,None)):
print line
Peut-être avec genexps. Pas joli mais ...
Quelque chose comme ca:
>>> gx = (line for line in '1 2 x 3 4 5 6 7 x 9 10 11 12 x 1'.split('\n'))
>>> for line in gx:
... if line == 'x':
... for i in range(2):
... line = gx.next()
... print line
Le seul problème est de s'assurer que gx peut être next () - ed. L'exemple ci-dessus génère volontairement une exception en raison du dernier x.