2012-09-29 12 views
8

Diamo 2 elencamodo fatest mescolare due liste in pitone

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

risultato:

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

Impossibile utilizzare zip() perché accorciare risultato al più piccolo list. Ho bisogno anche di un list all'uscita non di un iterable.

+0

Più veloce, più elegante o più pitonioso? –

risposta

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

Per consentire None valori da inserire nelle liste è possibile utilizzare la seguente modifica:

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

Non c'è bisogno di quella doppia parentesi lì. 'itertools.chain ((...))' può essere semplicemente 'itertools.chain (...)'. Oh e potresti voler incapsulare l'intera cosa in 'lista (...)'. – arshajii

7

Un'altra possibilità ...

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

(dopo l'importazione izip_longest da itertools, ovviamente)

+0

Questo è preferito anche se non il più descrittivo. :) – jathanism

0

Se è necessario l'output in una singola lista, invece di un lista di tuple, prova questo.

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

Nevermind, il metodo della catena itertools sta andando meglio. – 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:] 

questo non è un modo breve ma rimuove le dipendenze non necessarie.

aggiornamento: qui è un altro modo in cui è stata suggerita da @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 quali "dipendenze non necessarie" ti riferisci? L'unica altra dipendenza espressa finora da qualsiasi altra soluzione è 'itertools', che fa parte della libreria standard python. – inspectorG4dget

+0

sì ma deve ancora essere caricato dall'interprete. Non sto dicendo che le altre soluzioni non sono buone, probabilmente sono migliori per la maggior parte degli scopi, ma ho appena pubblicato un altro modo per farlo. –

0

Non pretendo che questo è il modo migliore per farlo, ma volevo solo far notare che è possibile utilizzare zip:

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

Tranne che non funzionerà in Python 3 come scritto, perché 'len (zip)' non è definito lì. – asmeurer

+1

Anche l'uso di una lista di comprensione per gli effetti collaterali è una cattiva idea. Usa invece '' itertools.chain() ''. –

2

il modo più semplice per farlo è quello di utilizzare la robin recipie rotonda dato in 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)) 

che può essere utilizzato in questo 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'] 

Nota che 2.x richiede una versione leggermente diversa di roundrobin, purché in the 2.x docs.

Questo evita anche il problema del metodo zip_longest() in quanto gli elenchi possono contenere None senza che venga rimosso.

+0

Non so se lo chiamerei il più semplice, considerando l'intera nuova funzione che devi definire per farlo funzionare. – asmeurer

+1

@asmeurer Trattandosi di una determinata ricetta, non è esattamente un problema includerla. Ha anche il vantaggio che menziono in basso - se la lista contiene '' None'' i metodi '' zip_longest() '' non funzionano come previsto. Davanti a un punto di vista dell'utilizzo, la funzione è chiara e semplice. –

+0

@Lattyware Ho aggiunto una semplice soluzione per il problema 'None' alla soluzione' izip_longest'. L'unico vantaggio che posso vedere con questo metodo ora è il vantaggio in termini di velocità di non dover scorrere iterate e scartare un gran numero di sentinelle. – 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

Presume che '' b'' sia più lungo di '' a'' - anche se può essere risolto con un altro codice. –