Danh sách chuyển đổi danh sách


241

Hãy thực hiện:

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

Kết quả tôi đang tìm kiếm là

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

và không

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

Nhiều đánh giá cao

Câu trả lời:


336

Làm thế nào về

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

Đối với người dùng python 3.x có thể sử dụng

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

Giải trình:

Có hai điều chúng ta cần biết để hiểu chuyện gì đang xảy ra:

  1. Chữ ký của zip : zip(*iterables)Điều này có nghĩa là zipmong đợi một số lượng đối số tùy ý mà mỗi đối số phải được lặp lại. Ví dụ zip([1, 2], [3, 4], [5, 6]).
  2. Danh sách đối số được giải nén : Đưa ra một chuỗi các đối số args, f(*args)sẽ gọi fsao cho mỗi phần tử trong argslà một đối số vị trí riêng biệt của f.

Quay trở lại đầu vào từ câu hỏi l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], zip(*l)sẽ tương đương với zip([1, 2, 3], [4, 5, 6], [7, 8, 9]). Phần còn lại chỉ là đảm bảo kết quả là một danh sách các danh sách thay vì một danh sách các bộ dữ liệu.


67
Chú ý: nếu lkhông có kích thước đồng đều (giả sử, một số hàng ngắn hơn các hàng khác), zipsẽ không bù cho nó và thay vào đó cắt đi các hàng khỏi đầu ra. Vì vậy, l=[[1,2],[3,4],[5]]cung cấp cho bạn [[1,3,5]].
badp

29
Các itertoolschức năng zip_longest()hoạt động với danh sách không đồng đều. Xem DOCS
Oregano

13
Một lời giải thích trong câu trả lời sẽ rất hay :)
Boris Churzin

7
Tôi nghĩ thậm chí list(zip(*l))hoạt động chính xác trong Python 3.
Stefano

3
@Stefano Nó hoạt động (như zip(*l)trong Python 2), nhưng bạn nhận được một danh sách các bộ dữ liệu, không phải danh sách các danh sách. Tất nhiên, list(list(it))luôn luôn là điều tương tự như list(it).
Alex Shpilkin

62

Một cách để làm điều đó là với chuyển đổi NumPy. Đối với một danh sách, một:

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

Hoặc một số khác không có zip:

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

8
Yêu người thứ hai của bạn - tôi không nhận ra mapcó thể làm điều đó. Đây là một sàng lọc nhỏ không yêu cầu 2 cuộc gọi, mặc dù:map(lambda *a: list(a), *l)
Lee D

7
Đây có nên là một câu trả lời tốt hơn vì nó quan tâm đến danh sách không đồng đều?
Leon

15
map(None, ...)dường như không hoạt động cho Py3. Trình tạo được tạo nhưng next()gây ra lỗi ngay lập tức : TypeError: 'NoneType' object is not callable.
Nhà vật lý điên

57

Tương đương với giải pháp của 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
Vì việc hiểu danh sách hiện được ưa thích hơn map(), giải pháp này là giải pháp phù hợp nhất với tinh thần Python ...
perror

26

chỉ để vui, hình chữ nhật hợp lệ và giả sử rằng m [0] tồn tại

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

đây là những gì tôi đang tìm kiếm và không thể quay đầu lại. Vẫn @ giải pháp Jena là thực sự ngắn
Titus

3
Vâng, phải mất một vài lốp xe để có được điều này đúng. Được rồi, nhiều cố gắng.
mai mối

9
Vẫn không hoàn toàn đúng - điều này chỉ xảy ra khi các kích thước là hình vuông! Nó nên là : [[j[i] for j in l] for i in range(len(l[0]))]. Tất nhiên, bạn phải chắc chắn rằng danh sách đó lkhông trống.
Lee D

@LeeD vẫn không hoạt động đối với tôi trên ví dụ của jena l = [[1,2], [3,4], [5]]
hobs

3
@hobs Đó là ví dụ của badp, trả lời jena. Tuy nhiên, tôi không chắc nó có ý nghĩa với tôi. IMO, hoán vị ngụ ý một ma trận hình chữ nhật - khi được biểu diễn dưới dạng danh sách các danh sách, điều đó có nghĩa là tất cả các danh sách nội bộ phải có cùng độ dài. Kết quả nào bạn muốn là "chuyển vị" của ví dụ này?
Lee D

22

Phương thức 1 và 2 hoạt động trong Python 2 hoặc 3 và chúng hoạt động trên các danh sách 2D hình chữ nhật rách rưới . Điều đó có nghĩa là các danh sách bên trong không cần phải có cùng độ dài với nhau (rách rưới) hoặc như các danh sách bên ngoài (hình chữ nhật). Các phương pháp khác, tốt, nó phức tạp.

thiết lập

import itertools
import six

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

phương pháp 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() trở thành

Giá trị mặc định là None. Nhờ câu trả lời của @ jena , nơi map()thay đổi các bộ dữ liệu bên trong thành danh sách. Ở đây nó đang biến các vòng lặp thành danh sách. Cảm ơn ý kiến của @ Oregano và @ badp .

Trong Python 3, chuyển kết quả qua list()để có được danh sách 2D giống như phương thức 2.


phương pháp 2 - hiểu danh sách, 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, '-']]

Các @ inspectorG4dget thay thế .


phương pháp 3 - map()của map()- bị hỏng trong 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]]

Giải pháp thay thế thứ hai @SiggyF cực kỳ nhỏ gọn này hoạt động với các danh sách 2D rách rưới, không giống như mã đầu tiên của anh ta sử dụng numpy để hoán vị và chuyển qua các danh sách rách rưới. Nhưng không có gì phải là giá trị điền. .

Ở đâu đó trong Python 3, map()đã ngừng đưa ra tất cả sự lạm dụng này: tham số đầu tiên không thể là Không có, và các trình vòng lặp rách rưới chỉ bị cắt ngắn nhất. Các phương thức khác vẫn hoạt động vì điều này chỉ áp dụng cho bản đồ bên trong ().


Phương pháp 4 - map()của 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+

Than ôi, các hàng rách rưới KHÔNG trở thành các cột rách rưới trong Python 3, chúng chỉ bị cắt cụt. Boo hoo tiến bộ.


7

Ba tùy chọn để chọn:

1. Bản đồ với Zip

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

2. Liệt kê danh sách

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

3. Để áp dụng vòng lặp

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

Và để xem kết quả:

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

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

0

Có thể không phải là giải pháp tao nhã nhất, nhưng đây là một giải pháp sử dụng các vòng lặp lồng nhau:

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() rất dễ đọc, và nó cũng hoạt động với máy phát điện.

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

hoặc tương đương

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

Đây là một giải pháp để hoán chuyển danh sách các danh sách không nhất thiết phải là hình vuông:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.