Liste der Listen transponieren

241

Lass uns nehmen:

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Das Ergebnis, das ich suche, ist

r = [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

und nicht

r = [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

Sehr geschätzt

Titus
quelle

Antworten:

336

Wie wäre es mit

map(list, zip(*l))
--> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Für Python 3.x können Benutzer verwenden

list(map(list, zip(*l)))

Erläuterung:

Es gibt zwei Dinge, die wir wissen müssen, um zu verstehen, was los ist:

  1. Die Signatur von zip : zip(*iterables)Dies bedeutet, zipdass eine beliebige Anzahl von Argumenten erwartet wird, von denen jedes iterierbar sein muss. ZB zip([1, 2], [3, 4], [5, 6]).
  2. Entpackten Argumentlisten : eine Folge von Argumenten angegeben args, f(*args)rufen , fso dass jedes Element in argseinem getrenntes Positions Argument f.

Auf die Eingabe aus der Frage zurückzukommen l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], zip(*l)wäre gleichbedeutend mit zip([1, 2, 3], [4, 5, 6], [7, 8, 9]). Der Rest stellt nur sicher, dass das Ergebnis eine Liste von Listen anstelle einer Liste von Tupeln ist.

Jena
quelle
67
Achtung: Wenn die lGröße nicht gleichmäßig ist (z. B. sind einige Zeilen kürzer als andere), zipwird dies nicht kompensiert und stattdessen werden Zeilen aus der Ausgabe entfernt. So l=[[1,2],[3,4],[5]]gibt es dir [[1,3,5]].
Badp
29
Die itertoolsFunktion zip_longest()arbeitet mit ungeraden Listen. Siehe DOCS
Oregano
13
Eine Erklärung als Antwort wäre schön :)
Boris Churzin
7
Ich denke, list(zip(*l))funktioniert sogar richtig in Python 3.
Stefano
3
@Stefano Es funktioniert (wie zip(*l)in Python 2), aber Sie erhalten eine Liste von Tupeln, keine Liste von Listen. Natürlich list(list(it))ist immer das Gleiche wie list(it).
Alex Shpilkin
62

Eine Möglichkeit ist die NumPy-Transponierung. Für eine Liste gilt Folgendes:

>>> import numpy as np
>>> np.array(a).T.tolist()
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Oder eine andere ohne Reißverschluss:

>>> map(list,map(None,*a))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
SiggyF
quelle
8
Liebe deinen zweiten - ich wusste nicht, mapdass ich das tun kann. Hier ist eine leichte Verfeinerung, die jedoch keine zwei Anrufe erfordert:map(lambda *a: list(a), *l)
Lee D
7
Sollte dies nicht eine bessere Antwort sein, da es sich um ungleichmäßige Listen handelt?
Leon
15
map(None, ...)scheint nicht für Py3 zu funktionieren. Der Generator wird erstellt, next()löst jedoch sofort einen Fehler aus : TypeError: 'NoneType' object is not callable.
Mad Physicist
57

Entsprechend Jenas Lösung:

>>> l=[[1,2,3],[4,5,6],[7,8,9]]
>>> [list(i) for i in zip(*l)]
... [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
inspectorG4dget
quelle
12
Da das Listenverständnis jetzt bevorzugt wird, map()ist diese Lösung diejenige, die am meisten im Python-Geist ist ...
Perror
26

Nur zum Spaß, gültige Rechtecke und unter der Annahme, dass m [0] existiert

>>> m = [[1,2,3],[4,5,6],[7,8,9]]
>>> [[row[i] for row in m] for i in range(len(m[0]))]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Matchew
quelle
Das ist es, wonach ich gesucht habe und meinen Kopf nicht herumbekommen habe. Trotzdem ist @ Jenas Lösung wirklich kurz
Titus
3
Ja, es dauerte ein paar Reifen, um das richtig zu machen. Okay, viele Versuche.
Matchew
9
Immer noch nicht ganz richtig - das funktioniert nur, wenn die Abmessungen quadratisch sind! Es sollte sein : [[j[i] for j in l] for i in range(len(l[0]))]. Natürlich müssen Sie sicherstellen, dass die Liste lnicht leer ist.
Lee D
@ LeeD funktioniert immer noch nicht für mich in Jenas Beispiel l = [[1,2], [3,4], [5]]
Kochfelder
3
@hobs Das war das Beispiel von Badp, als er auf Jena reagierte. Ich bin mir jedoch nicht sicher, ob es für mich Sinn macht. IMO impliziert die Transposition eine rechteckige Matrix - wenn sie als Liste von Listen dargestellt wird, bedeutet dies, dass alle internen Listen dieselbe Länge haben müssen. Welches Ergebnis möchten Sie als "Umsetzung" dieses Beispiels?
Lee D
22

Die Methoden 1 und 2 funktionieren in Python 2 oder 3 und in unregelmäßigen, rechteckigen 2D-Listen. Das bedeutet, dass die inneren Listen nicht die gleiche Länge haben müssen (zackig) oder wie die äußeren Listen (rechteckig). Die anderen Methoden sind kompliziert.

die Einrichtung

import itertools
import six

list_list = [[1,2,3], [4,5,6, 6.1, 6.2, 6.3], [7,8,9]]

Methode 1 - map(),zip_longest()

>>> list(map(list, six.moves.zip_longest(*list_list, fillvalue='-')))
[[1, 4, 7], [2, 5, 8], [3, 6, 9], ['-', 6.1, '-'], ['-', 6.2, '-'], ['-', 6.3, '-']]

six.moves.zip_longest() wird

Der Standardfüllwert ist None. Dank der Antwort von @ jena , wo map()die inneren Tupel in Listen geändert werden. Hier werden Iteratoren in Listen umgewandelt. Vielen Dank an die Kommentare von @ Oregano und @ badp .

Übergeben Sie in Python 3 das Ergebnis list(), um dieselbe 2D-Liste wie in Methode 2 zu erhalten.


Methode 2 - Listenverständnis, zip_longest()

>>> [list(row) for row in six.moves.zip_longest(*list_list, fillvalue='-')]
[[1, 4, 7], [2, 5, 8], [3, 6, 9], ['-', 6.1, '-'], ['-', 6.2, '-'], ['-', 6.3, '-']]

Die @ inspectorG4dget-Alternative .


Methode 3 - map()of map()- in Python 3.6 gebrochen

>>> map(list, map(None, *list_list))
[[1, 4, 7], [2, 5, 8], [3, 6, 9], [None, 6.1, None], [None, 6.2, None], [None, 6.3, None]]

Diese außerordentlich kompakte zweite Alternative von @SiggyF funktioniert mit zerlumpten 2D-Listen, im Gegensatz zu seinem ersten Code, der numpy verwendet, um zerlumpte Listen zu transponieren und zu durchlaufen. Aber keiner muss der Füllwert sein. (Nein, das an die innere Map () übergebene None ist nicht der Füllwert. Dies bedeutet, dass keine Funktion zum Verarbeiten jeder Spalte vorhanden ist. Die Spalten werden nur an die äußere Map () übergeben, die sie von Tupeln in Listen konvertiert.

Irgendwo in Python 3 wurde map()dieser Missbrauch nicht mehr ertragen: Der erste Parameter kann nicht None sein, und zerlumpte Iteratoren werden nur auf die kürzeste Zeit abgeschnitten. Die anderen Methoden funktionieren weiterhin, da dies nur für die innere Map () gilt.


Methode 4 - map()von map()überarbeitet

>>> list(map(list, map(lambda *args: args, *list_list)))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]   // Python 2.7
[[1, 4, 7], [2, 5, 8], [3, 6, 9], [None, 6.1, None], [None, 6.2, None], [None, 6.3, None]] // 3.6+

Leider werden die unregelmäßigen Zeilen in Python 3 NICHT zu unregelmäßigen Spalten, sondern nur abgeschnitten. Boo hoo Fortschritt.

Bob Stein
quelle
7

Drei Optionen zur Auswahl:

1. Karte mit Zip

solution1 = map(list, zip(*l))

2. Listenverständnis

solution2 = [list(i) for i in zip(*l)]

3. Zum Anhängen einer Schleife

solution3 = []
for i in zip(*l):
    solution3.append((list(i)))

Und um die Ergebnisse anzuzeigen:

print(*solution1)
print(*solution2)
print(*solution3)

# [1, 4, 7], [2, 5, 8], [3, 6, 9]
jasonleonhard
quelle
0

Vielleicht nicht die eleganteste Lösung, aber hier ist eine Lösung mit verschachtelten while-Schleifen:

def transpose(lst):
    newlist = []
    i = 0
    while i < len(lst):
        j = 0
        colvec = []
        while j < len(lst):
            colvec.append(lst[j][i])
            j = j + 1
        newlist.append(colvec)
        i = i + 1
    return newlist
Fußballmann2399
quelle
0
import numpy as np
r = list(map(list, np.transpose(l)))
reza.cse08
quelle
0

more_itertools.unzip() ist leicht zu lesen und funktioniert auch mit Generatoren.

import more_itertools
l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
r = more_itertools.unzip(l) # a tuple of generators.
r = list(map(list, r))      # a list of lists

oder gleichwertig

import more_itertools
l = more_itertools.chunked(range(1,10), 3)
r = more_itertools.unzip(l) # a tuple of generators.
r = list(map(list, r))      # a list of lists
Gott
quelle
-1

Hier ist eine Lösung zum Transponieren einer Liste von Listen, die nicht unbedingt quadratisch ist:

maxCol = len(l[0])
for row in l:
    rowLength = len(row)
    if rowLength > maxCol:
        maxCol = rowLength
lTrans = []
for colIndex in range(maxCol):
    lTrans.append([])
    for row in l:
        if colIndex < len(row):
            lTrans[colIndex].append(row[colIndex])
1man
quelle
-2
    #Import functions from library
    from numpy import size, array
    #Transpose a 2D list
    def transpose_list_2d(list_in_mat):
        list_out_mat = []
        array_in_mat = array(list_in_mat)
        array_out_mat = array_in_mat.T
        nb_lines = size(array_out_mat, 0)
        for i_line_out in range(0, nb_lines):
            array_out_line = array_out_mat[i_line_out]
            list_out_line = list(array_out_line)
            list_out_mat.append(list_out_line)
        return list_out_mat
SolarJonathan
quelle