działa tylko wtedy, gdy l1 i l2 mają taką samą liczbę elementów
Emmanuel
14
@Emmanuel: Pytanie brzmi: „Czy w Pythonie jest dobry sposób na przeplatanie dwóch list o tej samej długości ?”
NPE
1
Jeśli chcesz przejść do najdłuższej listy, użyj wyników izip_longestdla python2 i zip_longestdla python3 ` [val for pair in itertools.zip_longest(l1, l2) for val in pair]z['a', 'b', 'a', 'b', 'a', 'b', None, 'b', None, 'b', None, 'b']
>>> 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 + bsłuży jako prosty sposób na utworzenie nowej listy o dokładnie odpowiedniej długości (na tym etapie jej zawartość nie jest ważna). Kolejne dwie linie wykonują właściwą pracę polegającą na przeplataniu ai b: pierwsza przypisuje elementy awszystkich parzystych indeksów c; drugi przypisuje elementy bwszystkich indeksów o numerach nieparzystych c.
>>> l1=[1,2,3]
>>> l2=[10,20,30]
>>> [y for x in map(None,l1,l2) for y in x if y isnotNone]
[1, 10, 2, 20, 3, 30]
To działa, ponieważ mapa działa równolegle na listach. To działa tak samo w punkcie 2.2. Sam w sobie, wraz Nonez wywołanymi funkcjami, maptworzy listę krotek:
Zaletą jest oczywiście to, że map będzie działać dla dowolnej liczby list i będzie działać nawet jeśli mają 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 innotNone]
[1, 10, 101, 2, 20, 102, 3, 30, 103, 104]
if ybędzie również odfiltrowywać 0, if y is not Nonejest mniej kruchy.
Jochen Ritzel
@Jochen Ritzel: Dzięki! Zgadzam się z Tobą. Naprawiony. Napisałem to z zaangażowanymi tylko mięśniami ...
wilk
3
Najbardziej podoba mi się rozwiązanie aix. tutaj jest inny sposób, który moim zdaniem powinien 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]
i:
>>> sum((list(i) for i in zip(x,y)),[])
[0, 7, 1, 8, 2, 9]
Aby odpowiedzieć na tytuł pytania „Przeplataj wiele list o tej samej długości w Pythonie”, możemy uogólnić odpowiedź z 2 listami @ekhumoro. To wyraźnie wymaga, aby listy miały tę samą długość, w przeciwieństwie do (eleganckiego) rozwiązania @NPE
import itertools
definterleave(lists):"""Interleave a list of lists.
:param lists: List of lists; each inner length must be the same length.
:returns: interleaved single list
:rtype: list
"""if len(set(len(_) for _ in lists)) > 1:
raise ValueError("Lists are not all the same length!")
joint = list(itertools.chain(*lists))
for l_idx, li in enumerate(lists):
joint[l_idx::len(lists)] = li
return joint
it = iter(l1); list((yield next(it)) or i for i in l2)
Odpowiedzi:
Po opublikowaniu pytania zdałem sobie sprawę, że mogę po prostu wykonać następujące czynności:
[val for pair in zip(l1, l2) for val in pair]
gdzie
l1
il2
są dwie listy.Jeśli jest N list do przeplotu, to
lists = [l1, l2, ...] [val for tup in zip(*lists) for val in tup]
źródło
izip_longest
dla python2 izip_longest
dla python3 `[val for pair in itertools.zip_longest(l1, l2) for val in pair]
z['a', 'b', 'a', 'b', 'a', 'b', None, 'b', None, 'b', None, 'b']
Dla Pythona> = 2.3 istnieje rozszerzona składnia wycinka :
>>> 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 na utworzenie nowej listy o dokładnie odpowiedniej długości (na tym etapie jej zawartość nie jest ważna). Kolejne dwie linie wykonują właściwą pracę polegającą na przeplataniua
ib
: pierwsza przypisuje elementya
wszystkich parzystych indeksówc
; drugi przypisuje elementyb
wszystkich indeksów o numerach nieparzystychc
.źródło
Dany
a = [1, 2, 3] b = [10, 20, 30] c = [100, 200, 300, 999]
Kod
Zakładając listy o równej długości, możesz otrzymać listę przeplataną z
itertools.chain
izip
:import itertools list(itertools.chain(*zip(a, b))) # [1, 10, 2, 20, 3, 30]
Alternatywy
itertools.zip_longest
Bardziej ogólnie w przypadku nierównych list użyj
zip_longest
(zalecane):[x for x in itertools.chain(*itertools.zip_longest(a, c)) if x is not None] # [1, 100, 2, 200, 3, 300, 999]
Wiele list można bezpiecznie przeplatać:
[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
+Biblioteka dostarczana z
roundrobin
recepturą itertoolsinterleave
iinterleave_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
Na koniec coś ciekawego w Pythonie 3 (choć niezalecane):
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]
+ Zainstaluj za pomocą
pip install more_itertools
źródło
Potrzebowałem sposobu, aby to zrobić z listami o różnych rozmiarach, których nie dotyczy zaakceptowana odpowiedź.
Moje rozwiązanie wykorzystuje generator i dzięki temu jego użytkowanie wygląda trochę przyjemniej:
def interleave(l1, l2): iter1 = iter(l1) iter2 = iter(l2) while True: try: if iter1 is not None: yield next(iter1) except StopIteration: iter1 = None try: if iter2 is not None: yield next(iter2) except StopIteration: iter2 = None if iter1 is None and iter2 is None: raise StopIteration()
I jego zastosowanie:
>>> 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']
źródło
roundrobin
Przepis zitertools
modułu jest bardziej ogólny przedłużenie tego.Alternatywny:
>>> 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ż mapa działa równolegle na listach. To działa tak samo w punkcie 2.2. Sam w sobie, wraz
None
z wywołanymi funkcjami,map
tworzy listę krotek:>>> map(None,l1,l2,'abcd') [(1, 10, 'a'), (2, 20, 'b'), (3, 30, 'c'), (None, None, 'd')]
Następnie po prostu spłaszcz listę krotek.
Zaletą jest oczywiście to, że
map
będzie działać dla dowolnej liczby list i będzie działać nawet jeśli mają 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]
źródło
if y
będzie również odfiltrowywać0
,if y is not None
jest mniej kruchy.Najbardziej podoba mi się rozwiązanie aix. tutaj jest inny sposób, który moim zdaniem powinien 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]
i:
>>> sum((list(i) for i in zip(x,y)),[]) [0, 7, 1, 8, 2, 9]
źródło
[el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None]
Dopóki nie masz
None
tego, co chcesz zatrzymaćźródło
Aby odpowiedzieć na tytuł pytania „Przeplataj wiele list o tej samej długości w Pythonie”, możemy uogólnić odpowiedź z 2 listami @ekhumoro. To wyraźnie wymaga, aby listy miały tę samą długość, w przeciwieństwie do (eleganckiego) rozwiązania @NPE
import itertools def interleave(lists): """Interleave a list of lists. :param lists: List of lists; each inner length must be the same length. :returns: interleaved single list :rtype: list """ if len(set(len(_) for _ in lists)) > 1: raise ValueError("Lists are not all the same length!") joint = list(itertools.chain(*lists)) for l_idx, li in enumerate(lists): joint[l_idx::len(lists)] = li return joint
Przykłady:
>>> interleave([[0,2,4], [1, 3, 5]]) [0, 1, 2, 3, 4, 5] >>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12]]) [0, 1, 10, 2, 3, 11, 4, 5, 12] >>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12], [13, 14, 15]]) [0, 1, 10, 13, 2, 3, 11, 14, 4, 5, 12, 15] >>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12], [13, 14]]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 10, in interleave ValueError: Lists are not all the same length! >>> interleave([[0,2,4]]) [0, 2, 4]
źródło
Za późno na imprezę, a dobrych odpowiedzi jest mnóstwo, ale chciałbym też podać proste rozwiązanie
extend()
metodą:list1 = [1, 2, 3] list2 = [10, 20, 30] new_list = [] for i in range(len(list1)): new_list.extend([list1[i], list2[i]]) print(new_list)
Wynik:
[1, 10, 2, 20, 3, 30]
źródło