Lijst met lijsten transponeren

Laten we nemen:

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

Het resultaat dat ik zoek is

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

en niet

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

Zeer gewaardeerd


Antwoord 1, autoriteit 100%

Wat dacht je van

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

Voor python 3.x kunnen gebruikers

list(map(list, zip(*l))) # short circuits at shortest nested list if table is jagged
list(map(list, itertools.zip_longest(*l, fillvalue=None))) # discards no data if jagged and fills short nested lists with None

Uitleg:

Er zijn twee dingen die we moeten weten om te begrijpen wat er aan de hand is:

  1. De handtekening van zip: zip(*iterables)Dit betekent dat zipeen willekeurig aantal argumenten verwacht die elk itereerbaar moeten zijn. bijv. zip([1, 2], [3, 4], [5, 6]).
  2. Uitgepakte argumentlijsten: gegeven een reeks van argumenten args, f(*args)roept faan zodat elk element in argseen afzonderlijk positioneel argument is van f.
  3. itertools.zip_longestverwijdert geen gegevens als het aantal elementen van de geneste lijsten niet hetzelfde (homogeen) is en vult in plaats daarvan de kortere geneste lijsten in daarnaritst ze dicht.

Terugkomend op de invoer van de vraag l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], zip(*l)zou gelijk zijn aan zip([1, 2, 3], [4, 5, 6], [7, 8, 9]). De rest zorgt ervoor dat het resultaat een lijst met lijsten is in plaats van een lijst met tupels.


Antwoord 2, autoriteit 17%

Een manier om dit te doen is met NumPy transponeren. Voor een lijst, een:

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

Of een andere zonder ritssluiting:

>>> map(list,map(None,*a))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Antwoord 3, autoriteit 16%

Equivalent aan Jena’s oplossing:

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

Antwoord 4, autoriteit 7%

gewoon voor de lol, geldige rechthoeken en ervan uitgaande dat m[0] bestaat

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

Antwoord 5, autoriteit 6%

Methoden 1 en 2 werken in Python 2 of 3, en ze werken op rafelige, rechthoekige2D-lijsten. Dat betekent dat de binnenlijsten niet dezelfde lengte hoeven te hebben als elkaar (rafelig) of als de buitenste lijsten (rechthoekig). De andere methoden, nou ja, het is ingewikkeld.

de installatie

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

De standaard vulwaarde is None. Met dank aan @jena’s answer, waarbij map()de binnenste tupels verandert in lijsten. Hier verandert het iterators in lijsten. Met dank aan de reactiesvan @Oregano en @badp.

Geef in Python 3 het resultaat door list()om dezelfde 2D-lijst te krijgen als methode 2.


methode 2 — lijstbegrip, 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, '-']]

Het @inspectorG4dget alternatief.


methode 3 — map()van map()gebroken in Python 3.6

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

Dit buitengewoon compacte @SiggyF tweede alternatiefwerkt met rafelige 2D-lijsten, in tegenstelling tot zijn eerste code die numpy gebruikt om te transponeren en door gerafelde lijsten gaan. Maar Geen moet de vulwaarde zijn. (Nee, de Geen die is doorgegeven aan de binnenste map() is niet de vulwaarde. Het betekent dat er geen functie is om elke kolom te verwerken. De kolommen worden gewoon doorgegeven aan de buitenste kaart() die ze van tupels naar lijsten converteert.)

Ergens in Python 3, map()hield op met al dit misbruik: de eerste parameter kan geen Geen zijn, en rafelige iterators worden gewoon afgekapt tot de kortste. De andere methoden werken nog steeds omdat dit alleen van toepassing is op de inner map().


methode 4 — map()van map()herzien

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

Helaas worden de rafelige rijen GEEN rafelige kolommen in Python 3, ze worden gewoon afgekapt. Boehoe-voortgang.


Antwoord 6, autoriteit 2%

Drie opties om uit te kiezen:

1. Kaart met Zip

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

2. Lijstbegrip

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

3. Voor lus toevoegen

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

En om de resultaten te bekijken:

print(*solution1)
print(*solution2)
print(*solution3)
# [1, 4, 7], [2, 5, 8], [3, 6, 9]

Antwoord 7

import numpy as np
r = list(map(list, np.transpose(l)))

Antwoord 8

Misschien niet de meest elegante oplossing, maar hier is een oplossing met geneste while-lussen:

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

Antwoord 9

more_itertools.unzip()is gemakkelijk te lezen en werkt ook met 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

of gelijkwaardig

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

Antwoord 10

matrix = [[1,2,3],
          [1,2,3],
          [1,2,3],
          [1,2,3],
          [1,2,3],
          [1,2,3],
          [1,2,3]]
rows = len(matrix)
cols = len(matrix[0])
transposed = []
while len(transposed) < cols:
    transposed.append([])
    while len(transposed[-1]) < rows:
        transposed[-1].append(0)
for i in range(rows):
    for j in range(cols):
        transposed[j][i] = matrix[i][j]
for i in transposed:
    print(i)

Antwoord 11

Nog een manier voor vierkante matrix. Geen numpy, noch itertools, gebruik (effectieve) uitwisseling van elementen ter plaatse.

def transpose(m):
    for i in range(1, len(m)):
        for j in range(i):
            m[i][j], m[j][i] = m[j][i], m[i][j]

Antwoord 12

Hier is een oplossing voor het transponeren van een lijst met lijsten die niet noodzakelijk vierkant is:

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

Antwoord 13

   #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

Other episodes