Suppose I have
l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
How can I get a result like so?
r = [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
I know how to get
r = [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
but I must have lists as elements of the result.
Suppose I have
l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
How can I get a result like so?
r = [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
I know how to get
r = [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
but I must have lists as elements of the result.
(or to limit each "column" to the length of the shortest input "row")
In Python 3.x, use:
# short circuits at shortest nested list if table is jagged:
list(map(list, zip(*l)))
In Python 2.x, use:
# short circuits at shortest nested list if table is jagged:
map(list, zip(*l))
There are two important things to understand here:
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]).args, f(*args) will call f such that each element in args is a separate positional argument of f. Given l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], zip(*l) would be equivalent to zip([1, 2, 3], [4, 5, 6], [7, 8, 9]). See also: Expanding tuples into argumentsThe rest is just making sure the result is a list of lists instead of a list of tuples, by using map to create a list from each tuple.
To pad shorter rows with None values in the output, import itertools (this is in the standard library), and then:
In Python 3.x, use:
list(map(list, itertools.zip_longest(*l, fillvalue=None)))
In Python 2.x, use:
list(map(list, itertools.izip_longest(*l, fillvalue=None)))
l is not evenly sized (say, some rows are shorter than others), zip will not compensate for it and instead chop away rows from the output. So l=[[1,2],[3,4],[5]] gives you [[1,3,5]].list(zip(*l)) works correctly in Python 3.zip(*l) in Python 2), but you get a list of tuples, not a list of lists. Of course, list(list(it)) is always the same thing as list(it).list(itertools.zip_longest(*data)) the * modifier effectively converts zip to extract, reversing the operation of zip..Equivalently to Jena's solution:
>>> 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(), this solution is the one which is the most in the Python spirit...One way to do it is with NumPy transpose. For a list, a:
>>> import numpy as np
>>> np.array(l).T.tolist()
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Or another one without zip (python < 3):
>>> map(list, map(None, *l))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Or for python >= 3:
>>> list(map(lambda *x: list(x), *l))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
map could do that. Here's a slight refinement that doesn't require 2 calls, though: map(lambda *a: list(a), *l)map(None, ...) doesn't seem to work for Py3. The generator is created but next() raises an error immediately: TypeError: 'NoneType' object is not callable.just for fun, valid rectangles and assuming that m[0] exists
>>> 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]))]. Of course, you have to be sure that list l is not empty.Methods 1 and 2 work in Python 2 or 3, and they work on ragged, rectangular 2D lists. That means the inner lists do not need to have the same lengths as each other (ragged) or as the outer lists (rectangular). The other methods, well, it's complicated.
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() becomes
itertools.izip_longest() in Python 2itertools.zip_longest() in Python 3The default fillvalue is None. Thanks to @jena's answer, where map() is changing the inner tuples to lists. Here it is turning iterators into lists. Thanks to @Oregano's and @badp's comments.
In Python 3, pass the result through list() to get the same 2D list as method 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, '-']]
The @inspectorG4dget alternative.
map() of map() — broken 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]]
This extraordinarily compact @SiggyF second alternative works with ragged 2D lists, unlike his first code which uses numpy to transpose and pass through ragged lists. But None has to be the fill value. (No, the None passed to the inner map() is not the fill value. It means there is no function to process each column. The columns are just passed through to the outer map() which converts them from tuples to lists.)
Somewhere in Python 3, map() stopped putting up with all this abuse: the first parameter cannot be None, and ragged iterators are just truncated to the shortest. The other methods still work because this only applies to the inner map().
map() of 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+
Alas the ragged rows do NOT become ragged columns in Python 3, they are just truncated. Boo hoo progress.
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]
import numpy as np
r = list(map(list, np.transpose(l)))
np.transpose(l).tolist().more_itertools.unzip() is easy to read, and it also works with generators.
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
or equivalently
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)
Just for fun: If you then want to make them all into dicts.
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}]
# Simple example
array = [["a","b","c"],["1","2","3"]]
list(zip(*array)) # [('a', '1'), ('b', '2'), ('c', '3')]
# We can also zip strings since they're indexable
array = ["abc","123"]
list(zip(*array)) # [('a', '1'), ('b', '2'), ('c', '3')]
# We can zip more arrays
array = [["a","b","c"],["1","2","3"],[10,20,30]]
list(zip(*array)) # [('a', '1', 10), ('b', '2', 20), ('c', '3', 30)]
# Also zip returns tuples. Use map to convert to lists
list(map(list,zip(*array))) # [['a', '1'], ['b', '2'], ['c', '3']]
Here is a solution for transposing a list of lists that is not necessarily square:
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