Odpowiedzi:
Co powiesz na
map(list, zip(*l))
--> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
W przypadku python 3.x użytkownicy mogą korzystać
list(map(list, zip(*l)))
Wyjaśnienie:
Są dwie rzeczy, które musimy wiedzieć, aby zrozumieć, co się dzieje:
zip(*iterables)
Oznacza to, zip
że oczekuje dowolnej liczby argumentów, z których każdy musi być iterowalny. Np zip([1, 2], [3, 4], [5, 6])
.args
, f(*args)
wywoła f
takie, że każdy element args
jest osobnym argumentem pozycyjnym f
.Wracając do danych wejściowych z pytania l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
, zip(*l)
byłoby to równoważne z zip([1, 2, 3], [4, 5, 6], [7, 8, 9])
. Reszta to tylko upewnienie się, że wynikiem będzie lista list zamiast listy krotek.
list(zip(*l))
działa poprawnie w Pythonie 3.
zip(*l)
w Pythonie 2), ale dostajesz listę krotek, a nie listę list. Oczywiście list(list(it))
zawsze jest to samo, co list(it)
.
Jednym ze sposobów jest transpozycja NumPy. W przypadku listy:
>>> import numpy as np
>>> np.array(a).T.tolist()
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Lub inny bez zip:
>>> map(list,map(None,*a))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
map
, że mogę to zrobić. Oto niewielkie udoskonalenie, które nie wymaga 2 połączeń:map(lambda *a: list(a), *l)
map(None, ...)
wydaje się nie działać dla Py3. Generator jest tworzony, ale next()
natychmiast podnosi błąd: TypeError: 'NoneType' object is not callable
.
Równoważnie z rozwiązaniem Jeny:
>>> 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]]
map()
, to rozwiązanie jest najbardziej w duchu Pythona ...
tylko dla zabawy, prawidłowe prostokąty i przy założeniu, że istnieje m [0]
>>> 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]]
[[j[i] for j in l] for i in range(len(l[0]))]
. Oczywiście musisz upewnić się, że lista l
nie jest pusta.
Metody 1 i 2 działają w języku Python 2 lub 3 i działają na nierównych, prostokątnych listach 2D. Oznacza to, że listy wewnętrzne nie muszą mieć takich samych długości (nierówne) ani zewnętrznych (prostokątne). Inne metody są skomplikowane.
import itertools
import six
list_list = [[1,2,3], [4,5,6, 6.1, 6.2, 6.3], [7,8,9]]
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()
staje się
itertools.izip_longest()
w Python 2itertools.zip_longest()
w Python 3Domyślna wartość wypełnienia to None
. Dzięki @ Jeny odpowiedź , gdzie map()
zmienia wewnętrzne krotki do list. Tutaj zamienia iteratory w listy. Dzięki komentarzom @ Oregano i @ badp .
W Pythonie 3 przekaż wynik, list()
aby uzyskać tę samą listę 2D co metoda 2.
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, '-']]
Alternatywa @ inspectorG4dget .
map()
of map()
- broken w Pythonie 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]]
Ta niezwykle kompaktowa druga alternatywa @ SigigF działa z poszarpanymi listami 2D, w przeciwieństwie do jego pierwszego kodu, który używa numpy do transponowania i przechodzenia przez poszarpane listy. Ale Brak musi być wartością wypełnienia. (Nie, Brak przekazany do wewnętrznej mapy () nie jest wartością wypełnienia. Oznacza to, że nie ma funkcji przetwarzającej każdą kolumnę. Kolumny są właśnie przekazywane do zewnętrznej mapy (), która konwertuje je z krotek na listy.
Gdzieś w Pythonie 3 map()
przestałem znosić to nadużycie: pierwszym parametrem nie może być None, a nierówne iteratory są po prostu skracane do najkrótszych. Inne metody nadal działają, ponieważ dotyczy to tylko wewnętrznej mapy ().
map()
z map()
revisited>>> 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+
Niestety poszarpane rzędy NIE stają się poszarpanymi kolumnami w Pythonie 3, są one po prostu obcięte. Postęp boo hoo.
solution1 = map(list, zip(*l))
solution2 = [list(i) for i in zip(*l)]
solution3 = []
for i in zip(*l):
solution3.append((list(i)))
print(*solution1)
print(*solution2)
print(*solution3)
# [1, 4, 7], [2, 5, 8], [3, 6, 9]
Może nie jest to najbardziej eleganckie rozwiązanie, ale oto rozwiązanie wykorzystujące zagnieżdżone pętle while:
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
import numpy as np
r = list(map(list, np.transpose(l)))
more_itertools.unzip()
jest łatwy do odczytania i działa również z generatorami.
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
lub równoważnie
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
Oto rozwiązanie dla transpozycji listy list, która niekoniecznie jest kwadratowa:
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])
#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
l
nie jest równomiernie wielkości (powiedzmy, niektóre wiersze są krótsze niż w innych),zip
będzie nie zrekompensować to i zamiast posiekać z dala wiersze z wyjścia. Więcl=[[1,2],[3,4],[5]]
daje[[1,3,5]]
.