2011-10-30 16 views
39

Czy w Pythonie istnieje dobry sposób na przeplatanie dwóch list o tej samej długości?Przeplatanie dwóch list w Pythonie

Powiedz, że dostałem [1,2,3] i [10,20,30]. Chciałbym przekształcić te w [1,10,2,20,3,30].

+0

Zdajesz sobie sprawę, że 2.2 jest teraz masz dziesięć lat? Nie ma powodu, aby nadal go używać. –

+3

@ DanielRoseman: Tak. W tym przypadku nie mam wyboru. – NPE

+0

Niezalecane, ale spróbuj tego: 'it = iter (l1); list ((yield next (it)) lub i for for l2) ' –

Odpowiedz

59

Po zaksięgowaniu pytanie, zdałem sobie sprawę, że mogę po prostu wykonaj następujące czynności:

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

gdzie l1 i l2 są dwie listy.

+2

działa tylko wtedy, gdy l1 i l2 mają tę samą liczbę elementów – Emmanuel

+1

@ Emmanuel: Pytanie brzmi" W Pythonie, czy istnieje dobry sposób na przeplatanie dwóch list? ** tej samej długości **? " – NPE

+2

Dziękuję Myślę, że potrzebuję nowej pary okularów. – Emmanuel

1

Najbardziej lubię rozwiązanie aix. Oto inny sposób myślę powinny działać w 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 "<stdin>", line 1, in <module> 
TypeError: can only concatenate list (not "tuple") to list 
>>> sum(map(list,zip(x,y)),[]) 
[0, 7, 1, 8, 2, 9] 

i jeszcze jeden sposób:

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

oraz:

>>> sum((list(i) for i in zip(x,y)),[]) 
[0, 7, 1, 8, 2, 9] 
5

alternatywne:

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

to działa ponieważ map działa równolegle na listach. To works the same zgodnie z 2.2. Sama z None co zwanych funkcjami map tworzy listę krotek:

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

Następnie wystarczy spłaszczyć listę krotek.

Zaletą oczywiście jest map będzie pracować dla dowolnej liczby list i będzie działać, nawet jeśli są one różne długości:

>>> 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] 
+1

'jeśli y' odfiltruje również "0", "jeśli y nie jest żadnym" jest mniej kruche. –

+0

@Jochen Ritzel: Dzięki! Zgadzam się z Tobą. Naprawiony. Napisałem go tylko z zaangażowanymi mięśniami ... –

29

dla Pythona> = 2.3, istnieje extended slice syntax:

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

Linia c = a + b służy jako prosty sposób utworzenia nowej listy o dokładnie odpowiedniej długości (na tym etapie jej zawartość nie jest ważna). Następne dwa wiersze odpowiadają faktycznej pracy przeplatania a i b: pierwsza przypisuje elementy a do wszystkich indeksów parzystych o numerach c; drugi przypisuje elementy b do wszystkich nieparzystych indeksów c.

5

Potrzebowałem sposobu, aby to zrobić z listami o różnych rozmiarach, których akceptowana odpowiedź nie dotyczy.

Moje rozwiązanie używa generatora i jego użycie wygląda nieco ładniej z tego powodu:

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

i jego wykorzystania:

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

Istnieje kilka opcji.

# Given 
a = [1, 2, 3] 
b = [10, 20, 30] 

Można uzyskać listę przeplatanych z itertools:

import itertools 

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

Rozważ zainstalowanie more_itertools - biblioteka, która jest dostarczana z implementacjami interleave, interleave_longest i roundrobin itertools recipe.

import more_itertools 

list(more_itertools.interleave(a, b)) 
# [1, 10, 2, 20, 3, 30] 

list(more_itertools.roundrobin(a, b)) 
# [1, 10, 2, 20, 3, 30] 

Wreszcie coś ciekawego, w Pythonie 3:

list(filter(None, ((yield from i) for i in zip(a, b)))) 
# [1, 10, 2, 20, 3, 30] 
0
[el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None] 

Dopóki nie masz None że chcesz zachować