s = [1,2,3,4,5,6,7,8,9]
n = 3
zip(*[iter(s)]*n) # returns [(1,2,3),(4,5,6),(7,8,9)]
¿Cómo funciona zip(*[iter(s)]*n)
? ¿Qué aspecto tendría si estuviera escrito con un código más detallado?¿Cómo funciona zip (* [iter (s)] * n) en Python?
s = [1,2,3,4,5,6,7,8,9]
n = 3
zip(*[iter(s)]*n) # returns [(1,2,3),(4,5,6),(7,8,9)]
¿Cómo funciona zip(*[iter(s)]*n)
? ¿Qué aspecto tendría si estuviera escrito con un código más detallado?¿Cómo funciona zip (* [iter (s)] * n) en Python?
iter()
es un iterador sobre una secuencia. [x] * n
produce una lista que contiene n
cantidad de x
, es decir, una lista de longitud n
, donde cada elemento es x
. *arg
desempaqueta una secuencia en argumentos para una llamada de función. Por lo tanto, está pasando el mismo iterador 3 veces al zip()
, y extrae un elemento del iterador cada vez.
x = iter([1,2,3,4,5,6,7,8,9])
print zip(x, x, x)
iter(s)
devuelve un iterador para s.
[iter(s)]*n
hace una lista de n veces el mismo iterador para s.
Por lo tanto, al hacer zip(*[iter(s)]*n)
, extrae un elemento de los tres iteradores de la lista en orden. Como todos los iteradores son el mismo objeto, simplemente agrupa la lista en fragmentos de n
.
No 'n iteradores de la misma lista', pero 'n veces el mismo objeto iterador'. Los diferentes objetos iteradores no comparten el estado, incluso cuando pertenecen a la misma lista. –
Gracias, corregido. De hecho, eso era lo que estaba "pensando", pero escribí algo más. – sttwister
Las otras grandes respuestas y comentarios explican bien los roles de argument unpacking y zip().
Como Ignacio y ujukatzel decir, se pasa a zip()
tres referencias a la misma iterador y zip()
hace 3-tuplas de los enteros-fin-de cada referencia al iterador:
1,2,3,4,5,6,7,8,9 1,2,3,4,5,6,7,8,9 1,2,3,4,5,6,7,8,9
^ ^ ^
^ ^ ^
^ ^ ^
Y ya que usted pedir un código de ejemplo más detallado:
chunk_size = 3
L = [1,2,3,4,5,6,7,8,9]
# iterate over L in steps of 3
for start in range(0,len(L),chunk_size): # xrange() in 2.x; range() in 3.x
end = start + chunk_size
print L[start:end] # three-item chunks
Siguiendo los valores de start
y end
:
[0:3) #[1,2,3]
[3:6) #[4,5,6]
[6:9) #[7,8,9]
Fwiw, se puede obtener el mismo resultado con map()
con un argumento inicial de None
:
>>> map(None,*[iter(s)]*3)
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]
Para más información sobre zip()
y map()
: http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-zip/
No son tres copias del mismo iterador, es tres veces el mismo objeto iterador :) –
Un consejo para el uso postal presente camino. Truncará su lista si su longitud no es divisible de manera uniforme. Para solucionar este problema, puede usar itertools.izip_longest si puede aceptar valores de relleno.O usted podría utilizar algo como esto:
def n_split(iterable, n):
num_extra = len(iterable) % n
zipped = zip(*[iter(iterable)] * n)
return zipped if not num_extra else zipped + [iterable[-num_extra:], ]
de uso:
for ints in n_split(range(1,12), 3):
print ', '.join([str(i) for i in ints])
Prints:
1, 2, 3
4, 5, 6
7, 8, 9
10, 11
Esto ya está documentado en las recetas de 'itertools': http://docs.python.org/2/library/itertools.html#recipes' mero'. No es necesario reinventar la rueda – jamylak
Creo que una cosa que se perdió en todas las respuestas (probablemente obvio para aquellos familiarizados con iteradores) pero no tan obvio para otros es -
Como tenemos el mismo iterador, se obtiene s consumido y los elementos restantes son utilizados por el zip. Entonces, si simplemente usamos la lista y no el iter , por ej.
l = range(9)
zip(*([l]*3)) # note: not an iter here, the lists are not emptied as we iterate
# output
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6), (7, 7, 7), (8, 8, 8)]
Usando iterador, estallidos los valores y sólo mantiene restante disponible, así que para postal una vez que se consume 0 1 está disponible y luego 2 y así sucesivamente. ¡Una cosa muy sutil, pero bastante inteligente!
+1, ¡me salvaste! No puedo creer que otras respuestas omitieran este detalle vital suponiendo que todo el mundo lo sabe. ¿Puede dar alguna referencia a una documentación que incluye esta información? –
también eche un vistazo aquí donde también se explica cómo funciona: http://stackoverflow.com/questions/2202461/yield-multiple-objects-at-a-time-from-an-iterable-object/2202485# 2202485 –
si las respuestas aquí no son suficientes, lo publiqué aquí: http://telliott99.blogspot.com/2010/01/chunks-of-sequence-in-python.html – telliott99
Aunque es muy intrigante, esta técnica debe ir en contra el valor central de "legibilidad" de Python! – Demis