让我们来:

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

我想要的结果是

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

而不是

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

Python 3:

# short circuits at shortest nested list if table is jagged:
list(map(list, zip(*l)))

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

Python 2:

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

解释:

要了解发生了什么,我们需要知道两件事:

The signature of zip: zip(*iterables) This means zip expects an arbitrary number of arguments each of which must be iterable. E.g. zip([1, 2], [3, 4], [5, 6]). Unpacked argument lists: Given a sequence of arguments args, f(*args) will call f such that each element in args is a separate positional argument of f. itertools.zip_longest does not discard any data if the number of elements of the nested lists are not the same (homogenous), and instead fills in the shorter nested lists then zips them up.

回到问题l =[[1,2,3],[4,5,6],[7,8,9]]的输入,zip(*l)将等价于zip([1,2,3],[4,5,6],[7,8,9])。剩下的就是确保结果是列表的列表,而不是元组的列表。

一种方法是用NumPy转置。如需列出清单,请填写:

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

或者另一个没有zip (python < 3)的:

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

或者对于python >= 3:

>>> list(map(lambda *x: list(x), *l))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

等价于耶拿的解决方案:

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

只是为了好玩,有效的矩形假设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]]

也许不是最优雅的解决方案,但这里有一个使用嵌套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 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

方法1和2适用于Python 2或3,它们适用于不规则的矩形2D列表。这意味着内部列表彼此之间不需要具有相同的长度(粗糙的)或与外部列表(矩形的)相同的长度。其他的方法,很复杂。

设置

import itertools
import six

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

方法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()成为

Python中的itertools.izip_longest( itertools.zip_longest(

默认fillvalue为None。多亏了@jena的回答,where map()将内部元组更改为列表。这里它将迭代器转换为列表。感谢@Oregano和@badp的评论。

在Python 3中,将结果通过list()传递,以获得与方法2相同的2D列表。


方法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, '-']]

@inspectorG4dget替代。


method 3 - map()的map() -在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]]

这个非常紧凑的@SiggyF第二个替代方案使用粗糙的2D列表,不像他的第一个代码使用numpy来转置和传递粗糙的列表。但是None必须是填充值。(不,传递给内部map()的None不是填充值。这意味着没有函数来处理每一列。列只是传递给外部map(),它将它们从元组转换为列表。)

在Python 3的某个地方,map()不再容忍所有这些滥用:第一个形参不能为None,而不规则迭代器只是被截断为最短的迭代器。其他方法仍然有效,因为这只适用于内部map()。


方法4 - map()的map()重新访问

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

唉,在python3中,不规则的行不会变成不规则的列,它们只是被截断了。嘘嘘进步。

下面是一个不一定是平方的列表的转置的解决方案:

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

有三种选择:

1. Zip地图

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

2. 列表理解

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

3.For循环附加

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]
import numpy as np
r = list(map(list, np.transpose(l)))

More_itertools.unzip()很容易阅读,它也可以用于生成器。

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

或者同样的

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

方阵的另一种方法。不使用numpy和itertools,使用(有效的)就地元素交换。

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]

只是为了好玩:如果你想把它们都做成字典的话。

In [1]: l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
   ...: fruits = ["Apple", "Pear", "Peach",]
   ...: [dict(zip(fruits, j)) for j in [list(i) for i in zip(*l)]]
Out[1]:
[{'Apple': 1, 'Pear': 4, 'Peach': 7},
 {'Apple': 2, 'Pear': 5, 'Peach': 8},
 {'Apple': 3, 'Pear': 6, 'Peach': 9}]