bigote - diagrama de caja python
forma pitónica para iterar sobre parte de una lista (7)
Aunque itertools.islice
parece ser la solución óptima para este problema, de alguna manera, la importación adicional parece demasiado excesiva para algo tan simple.
Personalmente, considero que la solución enumerate
perfectamente legible y sucinta, aunque preferiría escribirla así:
for index, line in enumerate(lines):
if index >= 2:
foo(line)
Quiero iterar sobre todo en una lista, excepto los primeros elementos, por ejemplo:
for line in lines[2:]:
foo(line)
Esto es conciso, pero copia toda la lista, lo cual es innecesario. Yo podría hacer:
del lines[0:2]
for line in lines:
foo(line)
Pero esto modifica la lista, que no siempre es buena.
Puedo hacer esto:
for i in xrange(2, len(lines)):
line = lines[i]
foo(line)
Pero, eso es simplemente asqueroso.
Mejor podría ser esto:
for i,line in enumerate(lines):
if i < 2: continue
foo(line)
Pero no es tan obvio como el primer ejemplo.
Entonces, ¿cuál es la manera de hacerlo que es tan obvio como el primer ejemplo, pero no copia la lista innecesariamente?
La solución original es, en la mayoría de los casos, la adecuada.
for line in lines[2:]:
foo(line)
Si bien esto copia la lista, es solo una copia superficial, y es bastante rápida. No se preocupe por la optimización hasta que haya perfilado el código y haya encontrado que se trata de un cuello de botella.
Prefiero usar dropwhile para esto. Se siente natural después de usarlo en Haskell y en otros idiomas, y parece razonablemente claro. También puede usarlo en muchos otros casos en los que desee buscar una condición de "desencadenante" más compleja que el índice del elemento para el inicio de la iteración.
from itertools import dropwhile
for item in dropwhile(lambda x: x[0] < 2, enumerate(lst)):
# ... do something with item
Puede construir un generador auxiliar:
def rangeit(lst, rng):
for i in rng:
yield lst[i]
for e in rangeit(["A","B","C","D","E","F"], range(2,4)):
print(e)
Puedes probar itertools.islice(iterable[, start], stop[, step])
:
import itertools
for line in itertools.islice(list , start, stop):
foo(line)
def skip_heading( iterable, items ):
the_iter= iter( iterable ):
for i, e in enumerate(the_iter):
if i == items: break
for e in the_iter:
yield e
Ahora puede hacer for i in skip_heading( lines, 2 ):
sin preocuparse.
for fooable in (line for i,line in enumerate(lines) if i >= 2):
foo(fooable)