method - python itertools
python incrementando arbitrariamente un iterador dentro de un bucle (8)
Probablemente estoy haciendo esto de la manera incorrecta, pero me preguntaba cómo manejar esto en Python.
Primero un código c:
int i;
for(i=0;i<100;i++){
if(i == 50)
i = i + 10;
printf("%i/n", i);
}
Ok, nunca vemos los 50 ...
Mi pregunta es, ¿cómo puedo hacer algo similar en Python? Por ejemplo:
for line in cdata.split(''/n''):
if exp.match(line):
#increment the position of the iterator by 5?
pass
print line
Con mi experiencia limitada en python, solo tengo una solución, presento un contador y otra declaración if. rompa el ciclo hasta que el contador llegue a 5 después de exp.match (línea) es verdadero.
Tiene que haber una mejor forma de hacerlo, con suerte una que no implique la importación de otro módulo.
¡Gracias por adelantado!
itertools.islice :
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
Por ejemplo, si exp
, cdata
son:
exp = re.compile(r"skip5")
cdata = """
before skip
skip5
1 never see it
2 ditto
3 ..
4 ..
5 after skip
6
"""
Entonces la salida es:
before skip 5 after skip 6
Implementación de Python del ejemplo C
i = 0
while i < 100:
if i == 50:
i += 10
print i
i += 1
Como @ [Glenn Maynard] señaló en el comentario si necesita hacer saltos muy grandes como i + = 100000000, entonces debería usar un ciclo while
explícito en lugar de simplemente omitir los pasos en un ciclo for
.
Aquí está el ejemplo que usa explícito while
loop en lugar 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
Este ejemplo produce el mismo resultado que el ejemplo anterior de islice
.
Hay un paquete fantástico en Python llamado itertools
.
Pero antes de entrar en eso, sería útil explicar cómo se implementa el protocolo de iteración en Python. Cuando desee proporcionar iteración sobre su contenedor, especifique el método de clase __iter__()
que proporciona un tipo de iterador . "Entender el enunciado ''para'' de Python '' es un buen artículo que trata sobre cómo funciona realmente la declaración for-in
en Python y proporciona una buena descripción de cómo funcionan los tipos de iteradores.
Eche un vistazo a lo siguiente:
>>> sequence = [1, 2, 3, 4, 5]
>>> iterator = sequence.__iter__()
>>> iterator.next()
1
>>> iterator.next()
2
>>> for number in iterator:
print number
3
4
5
Ahora volvemos a itertools
. El paquete contiene funciones para varios propósitos de iteración. Si alguna vez necesitas hacer una secuencia especial, este es el primer lugar para mirar.
En la parte inferior, puede encontrar la sección de Recipes que contiene recetas para crear un conjunto de herramientas ampliado utilizando las herramientas de texto existentes como bloques de construcción .
Y hay una función interesante que hace exactamente lo que necesita:
def consume(iterator, n):
''''''Advance the iterator n-steps ahead. If n is none, consume entirely.''''''
collections.deque(itertools.islice(iterator, n), maxlen=0)
Aquí hay un ejemplo rápido y legible sobre cómo funciona (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
No estoy exactamente seguro de seguir su proceso de pensamiento, pero aquí hay algo de lo que alimentarme ...
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
No estoy seguro de lo que realmente está buscando, pero el rango (len (..)) debería ayudarlo.
No puedo analizar la pregunta bien porque hay un bloque de código C confuso e irrelevante. Por favor borralo.
Centrándose solo en el código de Python y la pregunta sobre cómo saltear 5 líneas ...
lineIter= iter( cdata.splitlines() )
for line in lineIter:
if exp.match(line):
for count in range(5):
line = lineIter.next()
print line
Puede soltar valores de un iterador
def dropvalues(iterator, vals):
for i in xrange(vals): iterator.next()
Ahora solo asegúrese de tener un objeto iterador para trabajar con lines = iter(cdata.split(''/n''))
; y recorrerlo.
Si lo haces con números, una lista de comprensión puede funcionar:
for i in [x for x in range(0, 99) if x < 50 and x > 59]:
print i
Sin embargo, mover un iterador hacia adelante es un poco más difícil. Sugeriría configurar su lista de antemano si no desea hacer el enfoque de contador, probablemente dividiendo cdata, luego trabajando en los índices de la línea coincidente y eliminando esa línea y las siguientes. Aparte de eso, estás atascado con el enfoque de contador que no es tan desagradable como lo haces para ser honesto.
Otra opción es esta:
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
Tal vez con genexps. No es bonito, pero ...
Algo como eso:
>>> 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
El único problema es asegurarse de que gx pueda ser el siguiente () - ed. El ejemplo anterior genera deliberadamente una excepción debido a la última x.
para su ejemplo, ya que está trabajando con listas (secuencias indexables) y no con iteradores, recomendaría lo siguiente:
lines = cdata.split("/n")
for line in lines[:50]+lines[60:]:
print line
ese no es el más eficiente ya que potencialmente construye 3 listas nuevas (pero si la parte omitida es más grande que la parte procesada, podría ser más eficiente que las otras opciones), pero es bastante clara y explícita.
Si no te importa usar el módulo itertools, puedes convertir fácilmente las listas en secuencias:
from itertools import chain, islice
for line in chain(islice(lines, None, 50), islice(lines, 60,None)):
print line