Transpose daftar daftar


241

Mari kita ambil:

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

Hasil yang saya cari adalah

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

dan tidak

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

Sangat dihargai

Jawaban:


337

Bagaimana tentang

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

Untuk python 3.x pengguna dapat menggunakan

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

Penjelasan:

Ada dua hal yang perlu kita ketahui untuk memahami apa yang terjadi:

  1. Tanda tangan zip : zip(*iterables)Ini berarti zipmengharapkan sejumlah argumen yang sewenang-wenang yang masing-masing harus dapat diubah. Misalnya zip([1, 2], [3, 4], [5, 6]).
  2. Daftar argumen yang tidak dibongkar : Diberikan urutan argumen args, f(*args)akan memanggil fsedemikian rupa sehingga setiap elemen dalam argsadalah argumen posisi terpisah f.

Kembali ke input dari pertanyaan l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], zip(*l)akan setara dengan zip([1, 2, 3], [4, 5, 6], [7, 8, 9]). Sisanya hanya memastikan hasilnya adalah daftar daftar bukan daftar tupel.


67
Hati-hati: jika lukurannya tidak merata (katakanlah, beberapa baris lebih pendek dari yang lain), tidakzip akan mengompensasi dan malah memotong baris dari output. Jadi memberimu . l=[[1,2],[3,4],[5]][[1,3,5]]
badp

29
The itertoolsfungsi zip_longest()bekerja dengan daftar yang tidak rata. Lihat DOCS
Oregano

13
Penjelasan dalam jawaban akan menyenangkan :)
Boris Churzin

7
Saya pikir bahkan list(zip(*l))berfungsi dengan benar dalam Python 3.
Stefano

3
@Stefano Berhasil (seperti halnya zip(*l)dalam Python 2), tetapi Anda mendapatkan daftar tupel, bukan daftar daftar. Tentu saja, list(list(it))selalu sama dengan list(it).
Alex Shpilkin

62

Salah satu cara untuk melakukannya adalah dengan transpos NumPy. Untuk daftar, a:

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

Atau yang lain tanpa zip:

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

8
Cintai yang kedua - saya tidak sadar mapbisa melakukan itu. Berikut adalah penyempurnaan sedikit yang tidak memerlukan 2 panggilan, meskipun:map(lambda *a: list(a), *l)
Lee D

7
Bukankah ini jawaban yang lebih baik karena menangani daftar yang tidak rata?
Leon

15
map(None, ...)sepertinya tidak berfungsi untuk Py3. Generator dibuat tetapi next()menimbulkan kesalahan segera: TypeError: 'NoneType' object is not callable.
Fisikawan Gila

57

Setara dengan solusi Jena:

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

12
Sebagai pemahaman daftar sekarang lebih disukai map(), solusi ini adalah salah satu yang paling dalam semangat Python ...
perror

26

hanya untuk bersenang-senang, persegi panjang yang valid dan dengan asumsi bahwa m [0] ada

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

ini adalah apa yang saya cari dan tidak bisa mendapatkan kepalaku. Solusi Still @ jena benar-benar singkat
titus

3
Ya, butuh beberapa ban untuk memperbaikinya. Oke, banyak yang mencoba.
cocok

9
Masih tidak sepenuhnya benar - ini hanya terjadi ketika dimensi persegi! Itu harus: [[j[i] for j in l] for i in range(len(l[0]))]. Tentu saja, Anda harus yakin daftar litu tidak kosong.
Lee D

@ LeeD masih tidak bekerja untuk saya pada contoh jena l = [[1,2], [3,4], [5]]
hobs

3
@hobs Itu contoh badp, merespons jena. Namun, saya tidak yakin itu masuk akal bagi saya. IMO, transposisi menyiratkan matriks persegi panjang - ketika direpresentasikan sebagai daftar daftar, itu berarti semua daftar internal harus sama panjangnya. Apa hasil yang Anda inginkan sebagai "transposisi" dari contoh ini?
Lee D

22

Metode 1 dan 2 bekerja di Python 2 atau 3, dan mereka bekerja pada daftar 2D persegi panjang yang kasar . Itu berarti daftar dalam tidak perlu memiliki panjang yang sama satu sama lain (compang-camping) atau sebagai daftar luar (persegi panjang). Metode lain, yah, itu rumit.

pengaturan

import itertools
import six

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

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

Nilai pengisian default adalah None. Terima kasih atas jawaban @ jena , di mana map()mengubah inner tuple menjadi daftar. Ini dia mengubah iterator menjadi daftar. Terima kasih atas komentar @ Oregano dan @ badp .

Dalam Python 3, lewati hasilnya list()untuk mendapatkan daftar 2D yang sama dengan metode 2.


metode 2 - daftar pemahaman, 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, '-']]

The @ inspectorG4dget alternatif .


metode 3 - map()of map()- broken dengan 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]]

Alternatif kedua @SiggyF yang luar biasa kompak ini bekerja dengan daftar 2D yang tidak rata, tidak seperti kode pertamanya yang menggunakan numpy untuk mentranspos dan melewati daftar yang tidak rata. Tapi Tidak ada yang harus menjadi nilai isi. (Tidak, Tidak ada yang diteruskan ke peta bagian dalam () bukan nilai isi. Ini berarti tidak ada fungsi untuk memproses setiap kolom. Kolom hanya diteruskan ke peta luar () yang mengonversinya dari tupel ke daftar.

Di suatu tempat di Python 3, map()berhenti memasang dengan semua penyalahgunaan ini: parameter pertama tidak boleh Tidak ada, dan iterator kasar hanya terpotong ke yang terpendek. Metode lain masih berfungsi karena ini hanya berlaku untuk peta bagian dalam ().


Metode 4 - map()dari map()ditinjau kembali

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

Sayangnya, baris yang tidak beraturan TIDAK menjadi kolom yang tidak rata dalam Python 3, mereka hanya terpotong. Boo hoo berlangsung.


7

Tiga opsi untuk dipilih:

1. Peta dengan Zip

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

2. Daftar Pemahaman

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

3. Untuk Tambah Lingkaran

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

Dan untuk melihat hasilnya:

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

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

0

Mungkin bukan solusi yang paling elegan, tapi inilah solusi menggunakan nested while loop:

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


0

more_itertools.unzip() mudah dibaca, dan juga berfungsi dengan generator.

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

atau setara

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

-1

Berikut adalah solusi untuk mentransposisi daftar daftar yang tidak harus kuadrat:

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

-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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.