2012-09-29 13 views
8

Rzućmy 2 listyfatest sposób zmieszać dwie listy w Pythonie

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

wynik:

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

Nie można użyć zip() ponieważ skrócić wynik najmniejszej list. Potrzebuję też list na wyjściu, a nie iterable.

+0

Najszybsza, najbardziej elegancka lub najbardziej pytona? –

Odpowiedz

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

Aby umożliwić None wartości mają być zawarte w wykazach można wykorzystać następujące zmiany:

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

Nie ma tam potrzeby podwójnego nawiasu. 'itertools.chain ((...))' może po prostu być 'itertools.chain (...)'. Och i możesz chcieć zamknąć całą rzecz na liście '(...)'. – arshajii

7

Inną możliwością ...

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

(po zaimportowaniu izip_longest z itertools, oczywiście)

+0

Jest to preferowane, nawet jeśli nie jest najbardziej opisowe. :) – jathanism

0

Jeśli potrzebujesz wyjścia na pojedynczej liście, zamiast na lista krotek, spróbuj tego.

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

Nevermind, metoda łańcucha itertools będzie lepsza. – 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:] 

to nie jest krótka droga, ale usuwa zbędne zależności.

zmiana: tutaj jest inny sposób, który został zaproponowany przez @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

Jakie "niepotrzebne zależności" masz na myśli? Jedyną inną zależnością wyrażoną dotychczas przez jakiekolwiek inne rozwiązanie jest 'itertools', która jest częścią standardowej biblioteki Pythona. – inspectorG4dget

+0

tak, ale wciąż musi być załadowany przez tłumacza. Nie mówię, że inne rozwiązania nie są dobre, są prawdopodobnie lepsze dla większości celów, ale właśnie napisałem inny sposób robienia tego. –

0

Nie twierdzę, że jest to najlepszy sposób to zrobić, ale chciałem podkreślić, że jest to możliwe używać Kod pocztowy:

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

Z wyjątkiem tego, że nie będzie działać w Pythonie 3, ponieważ napis 'len (zip)' nie jest tam zdefiniowany. – asmeurer

+1

Używanie rozumienia list do efektów ubocznych również jest złym pomysłem. Zamiast tego użyj '' itertools.chain() ''. –

2

Najprostszym sposobem, aby to zrobić jest użycie round robin receptur, podanego w 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)) 

które mogą być wykorzystywane w taki sposób:

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

Zauważ, że 2.x wymaga nieco innej wersji roundrobin, przewidzianego w the 2.x docs.

Pozwala to również uniknąć problemu z metodą zip_longest(), ponieważ listy mogą zawierać None bez usuwania.

+0

Nie wiem, czy nazwałbym to najprostszym, biorąc pod uwagę całą nową funkcję, którą musisz zdefiniować, aby działała. – asmeurer

+1

@asmeurer Ponieważ jest to dany przepis, dołączenie go nie jest trudnym zadaniem. Ma również zaletę, o której wspomnę na dole - jeśli lista zawiera '' None'', metody '' zip_longest() '' nie działają zgodnie z przeznaczeniem. Z przodu punktu widzenia użytkowania, funkcja jest jasna i prosta. –

+0

@Lattyware Dodałem prostą poprawkę do problemu 'Brak' do rozwiązania' izip_longest'. Jedyną korzyścią, jaką widzę teraz dzięki tej metodzie, jest przewaga prędkości polegająca na tym, że nie trzeba potencjalnie dokonywać iteracji i odrzucać dużej liczby wartowników. – 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

Zakłada się, że '' b'' jest dłuższe niż '' a'' - chociaż można to naprawić za pomocą jakiegoś dodatkowego kodu. –