2012-09-29 21 views
8

Tengamos 2 listasmanera fatest para mezclar dos listas en Python

l1 = [1, 2, 3] 
l2 = [a, b, c, d, e, f, g...] 

resultado:

list = [1, a, 2, b, 3, c, d, e, f, g...] 

No se puede utilizar zip() porque acortar resultado hasta el más mínimo list. También necesito un list en la salida no es iterable.

+0

¿Lo más rápido, lo más elegante o lo más pitónico? –

Respuesta

10
>>> l1 = [1,2,3] 
>>> l2 = ['a','b','c','d','e','f','g'] 
>>> [i for i in itertools.chain(*itertools.izip_longest(l1,l2)) if i is not None] 
[1, 'a', 2, 'b', 3, 'c', 'd', 'e', 'f', 'g'] 

Para permitir None valores que se incluirán en las listas que puede utilizar la siguiente modificación:

>>> from itertools import chain, izip_longest 
>>> l1 = [1, None, 2, 3] 
>>> l2 = ['a','b','c','d','e','f','g'] 
>>> sentinel = object() 
>>> [i 
    for i in chain(*izip_longest(l1, l2, fillvalue=sentinel)) 
    if i is not sentinel] 
[1, 'a', None, 'b', 2, 'c', 3, 'd', 'e', 'f', 'g'] 
+0

No hay necesidad de ese doble paréntesis allí. 'itertools.chain ((...))' puede ser simplemente 'itertools.chain (...)'. Ah, y es posible que desee encapsular todo en 'list (...)'. – arshajii

7

Otra posibilidad ...

[y for x in izip_longest(l1, l2) for y in x if y is not None] 

(después de importar izip_longest de itertools, por supuesto)

+0

Esto se prefiere incluso si no es el más descriptivo. :) – jathanism

0

Si necesita la salida en una sola lista, en lugar de una lista de tuplas, prueba esto.

Out=[] 
[(Out.extend(i) for i in (itertools.izip_longest(l1,l2))] 
Out=filter(None, Out) 
+0

No importa, el método de la cadena itertools será mejor. – Perkins

1
minLen = len(l1) if len(l1) < len(l2) else len(l2) 
for i in range(0, minLen): 
    list[2*i] = l1[i] 
    list[2*i+1] = l2[i] 
list[i*2+2:] = l1[i+1:] if len(l1) > len(l2) else l2[i+1:] 

esto no es un camino corto pero elimina dependencias innecesarias.

actualización: aquí es otra forma en que fue sugerido por @jsvk

mixed = [] 
for i in range(len(min(l1, l2))): 
    mixed.append(l1[i]) 
    mixed.append(l2[i]) 
list += max(l1, l2)[i+1:] 
+0

¿A qué "dependencias innecesarias" se está refiriendo? La única otra dependencia expresada por cualquier otra solución aquí hasta ahora es 'itertools', que es parte de la biblioteca estándar de python. – inspectorG4dget

+0

sí, pero todavía tiene que ser cargado por el intérprete. No digo que las otras soluciones no sean buenas, probablemente sean mejores para la mayoría de los propósitos, pero acabo de publicar otra forma de hacerlo. –

0

No pretendo que esta es la mejor manera de hacerlo, pero yo sólo quería señalar que es posible utilizar postal:

b = zip(l1, l2) 
a = [] 
[a.extend(i) for i in b] 
a.extend(max([l1, l2], key=len)[len(b):]) 

>>> a 
[1, 'a', 2, 'b', 3, 'c', 'd', 'e', 'f', 'g'] 
+0

Excepto que no funcionará en Python 3 como está escrito, porque 'len (zip)' no está definido allí. – asmeurer

+1

Usar una lista de comprensión de los efectos secundarios también es una mala idea. Use '' itertools.chain() '' en su lugar. –

2

la forma más sencilla de hacer esto es utilizar el robin recipie vuelta dada en the itertools docs:

def roundrobin(*iterables): 
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C" 
    # Recipe credited to George Sakkis 
    pending = len(iterables) 
    nexts = cycle(iter(it).__next__ for it in iterables) 
    while pending: 
     try: 
      for next in nexts: 
       yield next() 
     except StopIteration: 
      pending -= 1 
      nexts = cycle(islice(nexts, pending)) 

que se pueden utilizar de este modo:

>>> l1 = [1,2,3] 
>>> l2 = ["a", "b", "c", "d", "e", "f", "g"] 
>>> list(roundrobin(l1, l2)) 
[1, 'a', 2, 'b', 3, 'c', 'd', 'e', 'f', 'g'] 

Tenga en cuenta que 2.x requiere una versión ligeramente diferente de roundrobin, proporcionado en the 2.x docs.

Esto también evita el problema que tiene el método zip_longest() en que las listas pueden contener None sin que se eliminen.

+0

No sé si llamaría eso al más simple, teniendo en cuenta la nueva función que tiene que definir para que funcione. – asmeurer

+1

@asmeurer Como es una receta dada, no es exactamente una dificultad incluirla. También tiene el beneficio que menciono en la parte inferior: si la lista contiene '' Ninguno'', los métodos '' zip_longest() '' no funcionan como se esperaba. Frente a un punto de vista de uso, la función es clara y simple. –

+0

@Lattyware Agregué una solución simple para el problema 'Ninguno' a la solución' izip_longest'. La única ventaja que puedo ver con este método ahora es la ventaja de velocidad de no tener que iterar potencialmente y descartar una gran cantidad de centinelas. – jamylak

0
>>> a = [1, 2, 3] 
>>> b = list("abcdefg") 
>>> [x for e in zip(a, b) for x in e] + b[len(a):] 
[1, 'a', 2, 'b', 3, 'c', 'd', 'e', 'f', 'g'] 
+0

Esto supone que '' b'' es más largo que '' a'', aunque puede corregirse con más código. –

Cuestiones relacionadas