Intercale múltiples listas de la misma longitud en Python

En Python, ¿hay una buena manera de intercalar dos listas de la misma longitud?

Digamos que me dan [1,2,3] y [10,20,30] . Me gustaría transformarlos en [1,10,2,20,3,30] .

Después de publicar la pregunta, me di cuenta de que simplemente puedo hacer lo siguiente:

 [val for pair in zip(l1, l2) for val in pair] 

donde l1 y l2 son las dos listas.


Si hay N listas para intercalar, entonces

 lists = [l1, l2, ...] [val for tup in zip(*lists) for val in tup] 

Para obtener más recetas, siga la Mejor manera de intercalar una lista con sus valores de sufijo . Algunos de los métodos demostrados allí pueden generalizarse a dos o más listas de igual longitud.

Para python> = 2.3, hay una syntax de corte extendida :

 >>> a = [0, 2, 4, 6, 8] >>> b = [1, 3, 5, 7, 9] >>> c = a + b >>> c[::2] = a >>> c[1::2] = b >>> c [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

La línea c = a + b se utiliza como una forma sencilla de crear una nueva lista de la longitud exacta exacta (en esta etapa, su contenido no es importante). Las siguientes dos líneas hacen el trabajo real de intercalar a y b : la primera asigna los elementos de a a todos los índices pares de c ; el segundo asigna los elementos de b a todos los índices impares de c .

Dado

 a = [1, 2, 3] b = [10, 20, 30] c = [100, 200, 300, 999] 

Código

Suponiendo listas de igual longitud, puede obtener una lista intercalada con itertools.chain y zip :

 import itertools list(itertools.chain(*zip(a, b))) # [1, 10, 2, 20, 3, 30] 

Alternativas

itertools.zip_longest

En general, con listas desiguales, use zip_longest (recomendado):

 [x for x in itertools.chain(*itertools.zip_longest(a, c)) if x is not None] # [1, 100, 2, 200, 3, 300, 999] 

Muchas listas se pueden intercalar con seguridad:

 [x for x in itertools.chain(*itertools.zip_longest(a, b, c)) if x is not None] # [1, 10, 100, 2, 20, 200, 3, 30, 300, 999] 

more_itertools +

Una biblioteca que se roundrobin con la receta de roundrobin roundrobin, se interleave y se interleave_longest .

 import more_itertools list(more_itertools.roundrobin(a, b)) # [1, 10, 2, 20, 3, 30] list(more_itertools.interleave(a, b)) # [1, 10, 2, 20, 3, 30] list(more_itertools.interleave_longest(a, c)) # [1, 100, 2, 200, 3, 300, 999] 

yield from

Finalmente, para algo interesante en Python 3 (aunque no se recomienda):

 list(filter(None, ((yield from x) for x in zip(a, b)))) # [1, 10, 2, 20, 3, 30] list([(yield from x) for x in zip(a, b)]) # [1, 10, 2, 20, 3, 30] 

+ Instalar usando pip install more_itertools

Alternativa:

 >>> l1=[1,2,3] >>> l2=[10,20,30] >>> [y for x in map(None,l1,l2) for y in x if y is not None] [1, 10, 2, 20, 3, 30] 

Esto funciona porque el mapa funciona en listas en paralelo. Funciona igual bajo el 2.2. Por sí mismo, con None como las funciones llamadas, el map produce una lista de tuplas:

 >>> map(None,l1,l2,'abcd') [(1, 10, 'a'), (2, 20, 'b'), (3, 30, 'c'), (None, None, 'd')] 

Luego simplemente aplanar la lista de tuplas.

La ventaja, por supuesto, es que el map funcionará para cualquier número de listas y funcionará incluso si tienen diferentes longitudes:

 >>> l1=[1,2,3] >>> l2=[10,20,30] >>> l3=[101,102,103,104] >>> [y for x in map(None,l1,l2,l3) for y in x if y in not None] [1, 10, 101, 2, 20, 102, 3, 30, 103, 104] 

Necesitaba una forma de hacer esto con listas de diferentes tamaños que la respuesta aceptada no aborda.

Mi solución usa un generador y su uso se ve un poco mejor debido a esto:

 def interleave(l1, l2): iter1 = iter(l1) iter2 = iter(l2) while True: try: if iter1 != None: yield next(iter1) except StopIteration: iter1 = None try: if iter2 != None: yield next(iter2) except StopIteration: iter2 = None if iter1 == None and iter2 == None: raise StopIteration() 

Y su uso:

 >>> a = [1, 2, 3, 4, 5] >>> b = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> list(interleave(a, b)) [1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 'e', 'f', 'g'] >>> list(interleave(b, a)) ['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 'g'] 

Me gusta más la solución de aix. Aquí hay otra forma en la que creo que debería funcionar en 2.2:

 >>> x=range(3) >>> x [0, 1, 2] >>> y=range(7,10) >>> y [7, 8, 9] >>> sum(zip(x,y),[]) Traceback (most recent call last): File "", line 1, in  TypeError: can only concatenate list (not "tuple") to list >>> sum(map(list,zip(x,y)),[]) [0, 7, 1, 8, 2, 9] 

Y una forma más:

 >>> a=[x,y] >>> [a[i][j] for j in range(3) for i in (0,1)] [0, 7, 1, 8, 2, 9] 

y:

 >>> sum((list(i) for i in zip(x,y)),[]) [0, 7, 1, 8, 2, 9] 
 [el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None] 

Mientras no tengas None que quieras conservar