Verschachteln Sie in Python mehrere Listen gleicher Länge

85

Gibt es in Python eine gute Möglichkeit, zwei Listen gleicher Länge zu verschachteln?

Sagen Sie, ich bin gegeben [1,2,3]und [10,20,30]. Ich würde diese gerne in verwandeln [1,10,2,20,3,30].

NPE
quelle
Nicht empfohlen, aber versuchen Sie dies:it = iter(l1); list((yield next(it)) or i for i in l2)
Chris_Rands

Antworten:

112

Nachdem ich die Frage gestellt habe, habe ich festgestellt, dass ich einfach Folgendes tun kann:

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

wo l1und l2sind die beiden Listen.


Wenn N Listen verschachtelt werden müssen, dann

lists = [l1, l2, ...]
[val for tup in zip(*lists) for val in tup]
NPE
quelle
5
funktioniert nur, wenn l1 und l2 die gleiche Anzahl von Elementen haben
Emmanuel
14
@ Emmanuel: Die Frage lautet: "Gibt es in Python eine gute Möglichkeit, zwei Listen gleicher Länge zu verschachteln ?"
NPE
1
Wenn Sie zur längsten Liste izip_longestauffüllen zip_longestmöchten , verwenden Sie für python2 und für python3 `Ergebnisse [val for pair in itertools.zip_longest(l1, l2) for val in pair]mit['a', 'b', 'a', 'b', 'a', 'b', None, 'b', None, 'b', None, 'b']
Sergey Zakharov
71

Für Python> = 2.3 gibt es eine erweiterte 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]

Die Zeile c = a + bwird auf einfache Weise verwendet, um eine neue Liste mit genau der richtigen Länge zu erstellen (in diesem Stadium ist der Inhalt nicht wichtig). Die nächsten beiden Zeilen erledigen die eigentliche Arbeit der Verschachtelung aund b: Die erste Zeile ordnet die Elemente von aallen geradzahligen Indizes von zu c; Der zweite ordnet die Elemente von ballen ungeradzahligen Indizes von zu c.

ekhumoro
quelle
25

Gegeben

a = [1, 2, 3]
b = [10, 20, 30]
c = [100, 200, 300, 999]

Code

Unter der Annahme von Listen gleicher Länge können Sie eine verschachtelte Liste mit itertools.chainund erhalten zip:

import itertools


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

Alternativen

itertools.zip_longest

Allgemeiner bei ungleichen Listen verwenden zip_longest(empfohlen):

[x for x in itertools.chain(*itertools.zip_longest(a, c)) if x is not None]
# [1, 100, 2, 200, 3, 300, 999]

Viele Listen können sicher verschachtelt werden:

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

Eine Bibliothek, die mit dem roundrobinRezept itertools geliefert wird, interleaveund interleave_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

Zum Schluss noch etwas Interessantes in Python 3 (obwohl nicht empfohlen):

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]

+ Installieren mitpip install more_itertools

Pylang
quelle
8

Ich brauchte einen Weg, dies mit Listen unterschiedlicher Größe zu tun, die in der akzeptierten Antwort nicht angesprochen werden.

Meine Lösung verwendet einen Generator und seine Verwendung sieht deshalb etwas besser aus:

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

Und seine Verwendung:

>>> 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']
Sandy Chapman
quelle
Das roundrobinRezept aus dem itertoolsModul ist eine allgemeinere Erweiterung davon.
ShadowRanger
7

Alternative:

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

Dies funktioniert, weil Map parallel auf Listen arbeitet. Es funktioniert genauso unter 2.2. Mit Noneden aufgerufenen Funktionen mapwird eine Liste von Tupeln erstellt:

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

Dann reduzieren Sie einfach die Liste der Tupel.

Der Vorteil ist natürlich, dass es map für eine beliebige Anzahl von Listen funktioniert und auch dann, wenn sie unterschiedlich lang sind:

>>> 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]
der Wolf
quelle
1
if ywird auch herausfiltern 0, if y is not Noneist weniger zerbrechlich.
Jochen Ritzel
@Jochen Ritzel: Danke! Ich stimme mit Ihnen ein. Fest. Ich schrieb es nur mit Muskeln beschäftigt ...
der Wolf
3

Die Lösung von aix gefällt mir am besten. Hier ist eine andere Möglichkeit, die meiner Meinung nach in 2.2 funktionieren sollte:

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

und noch ein Weg:

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

und:

>>> sum((list(i) for i in zip(x,y)),[])
[0, 7, 1, 8, 2, 9]
Robert King
quelle
0
[el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None]

Solange du das nicht hast None, willst du es behalten

jon_darkstar
quelle
0

Um den Titel der Frage "Verschachteln Sie mehrere Listen gleicher Länge in Python" zu beantworten, können Sie die 2-Listen-Antwort von @ekhumoro verallgemeinern. Dies erfordert ausdrücklich, dass die Listen im Gegensatz zur (eleganten) Lösung von @NPE dieselbe Länge haben

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

Beispiele:

>>> 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]
Gl
quelle
0

Zu spät zur Party, und es gibt viele gute Antworten, aber ich möchte auch eine einfache Lösung mit der extend()Methode anbieten:

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)

Ausgabe:

[1, 10, 2, 20, 3, 30]
Amit Yadav
quelle