empty - python list append
Manera pitónica de devolver la lista de cada enésimo artículo en una lista más grande (9)
Digamos que tenemos una lista de números del 0 al 1000. ¿Existe una manera pitónica / eficiente de producir una lista del primer y cada 10º elemento subsecuente, es decir [0, 10, 20, 30, ... ]
?
Sí, puedo hacer esto usando un bucle for, pero me pregunto si hay una manera más clara de hacerlo, tal vez incluso en una línea.
-
source_list[::10]
es el más obvio, pero esto no funciona para ningún iterable y no es eficiente desde el punto de vista de la memoria para listas grandes. -
itertools.islice(source_sequence, 0, None, 10)
funciona para cualquier iterable y es eficiente, pero probablemente no es la solución más rápida para grandes listas y grandes pasos. -
(source_list[i] for i in xrange(0, len(source_list), 10))
¿Por qué no usar simplemente un parámetro de paso de la función de rango para obtener:
l = range(0, 1000, 10)
Para la comparación, en mi máquina:
H:/>python -m timeit -s "l = range(1000)" "l1 = [x for x in l if x % 10 == 0]"
10000 loops, best of 3: 90.8 usec per loop
H:/>python -m timeit -s "l = range(1000)" "l1 = l[0::10]"
1000000 loops, best of 3: 0.861 usec per loop
H:/>python -m timeit -s "l = range(0, 1000, 10)"
100000000 loops, best of 3: 0.0172 usec per loop
Aquí hay una mejor implementación de una lista de comprensión de "cada 10º elemento", que no usa los contenidos de la lista como parte de la prueba de membresía:
>>> l = range(165)
>>> [ item for i,item in enumerate(l) if i%10==0 ]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160]
>>> l = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
>>> [ item for i,item in enumerate(l) if i%10==0 ]
[''A'', ''K'', ''U'']
Pero esto es aún mucho más lento que el simple uso de list slicing.
Del manual: s[i:j:k] slice of s from i to j with step k
li = range(100)
sub = li[0::10]
>>> sub
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
Las comprensiones de listas están hechas exactamente para eso:
smaller_list = [x for x in range(100001) if x % 10 == 0]
Puede obtener más información sobre ellos en la documentación oficial de python: http://docs.python.org/tutorial/datastructures.html#list-comprehensions
Puede usar el operador de división de la siguiente manera:
l = [1,2,3,4,5]
l2 = l[::2] # get subsequent 2nd item
>>> l = range(165)
>>> l[0::10]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160]
EDITAR: solo por diversión, una pequeña comparación de tiempo (ignorando la condición de límite):
$ python -m timeit -s "l = range(1000)" "l1 = [x for x in l if x % 10 == 0]"
1000 loops, best of 3: 525 usec per loop
$ python -m timeit -s "l = range(1000)" "l1 = l[0::10]"
100000 loops, best of 3: 4.02 usec per loop
existing_list = range(0, 1001)
filtered_list = [i for i in existing_list if i % 10 == 0]
newlist = oldlist[::10]
Esto selecciona cada décimo elemento de la lista.