python iterator

range python



¿Cómo funciona zip(*[iter(s)]*n) en Python? (5)

Creo que una cosa que se ha omitido en todas las respuestas (probablemente obvia para quienes están familiarizados con los iteradores) pero no tan obvio para los demás es:

Como tenemos el mismo iterador, se consume y el zip usa los elementos restantes. Entonces, si simplemente usamos la lista y no la iter, por ejemplo.

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)]

Al usar el iterador, aparece los valores y solo queda disponible, por lo que para el zip una vez que se consume 0, 1 está disponible y luego 2, y así sucesivamente. ¡Una cosa muy sutil, pero bastante inteligente!

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?


Las otras excelentes respuestas y comentarios explican bien los roles del argumento desempaquetar y zip() .

Como dicen Ignacio y ujukatzel , pasas a zip() tres referencias al mismo iterador y zip() hace 3-tuplas de los enteros-en orden-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 pides una muestra de código 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, 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 el map() : http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-zip/


Una palabra de consejo para usar zip de esta manera. Truncará su lista si su longitud no es divisible de manera uniforme. Para itertools.izip_longest este problema, puede usar itertools.izip_longest si puede aceptar valores de relleno. O podrías usar 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:], ]

Uso:

for ints in n_split(range(1,12), 3): print '', ''.join([str(i) for i in ints])

Huellas dactilares:

1, 2, 3 4, 5, 6 7, 8, 9 10, 11


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 descomprime una secuencia en argumentos para una llamada de función. Por lo tanto, está pasando el mismo iterador 3 veces a 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.

Entonces, 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 .