397

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.

15 Answers 15

567

For rectangular data

(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:

  1. 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]).
  2. 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. 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 arguments

The 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.

For jagged data

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)))
Sign up to request clarification or add additional context in comments.

5 Comments

Beware: if 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]].
The itertools function zip_longest() works with uneven lists. See DOCS
I think even list(zip(*l)) works correctly in Python 3.
@Stefano It works (as does 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).
Simpler version that worked for me is. list(itertools.zip_longest(*data)) the * modifier effectively converts zip to extract, reversing the operation of zip..
116

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

2 Comments

As list comprehension is now preferred to map(), this solution is the one which is the most in the Python spirit...
85

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

6 Comments

Love your second one -- I didn't realize map could do that. Here's a slight refinement that doesn't require 2 calls, though: map(lambda *a: list(a), *l)
Shouldnt this be a better answer as it takes care of uneven lists?
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.
@Lee D please can you explain how the code returns expected data --> map(lambda *a: list(a), *l)
The numpy solution does not do jagged lists.
|
29

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

8 Comments

this is what I was looking for and couldn't get my head around. Still @jena's solution is really short
Yeah, it took a few tires to get this right. Okay, many tries.
Still isn't quite right -- this only happens to work when the dimensions are square! It should be: [[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.
@LeeD still doesn't work for me on jena's example l=[[1,2],[3,4],[5]]
@hobs That was badp's example, responding to jena. However, I'm not sure it makes sense to me. IMO, transposition implies a rectangular matrix -- when represented as a list of lists, that means all the internal lists must be the same length. What result would you want as the "transposition" of this example?
|
28

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.

the setup

import itertools
import six

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

method 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() becomes

The 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.

method 2 — list comprehension, 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.

method 3 — 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().

method 4 — 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.

Comments

8

Three options to choose from:

1. Map with Zip

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

2. List Comprehension

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

3. For Loop Appending

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

And to view the results:

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

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

Comments

2
import numpy as np
r = list(map(list, np.transpose(l)))

1 Comment

Alternative: np.transpose(l).tolist().
1

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

Comments

0

Maybe not the most elegant solution, but here's a solution using nested while loops:

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

Comments

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

Comments

0

One more way for square matrix. No numpy, nor itertools, use (effective) in-place elements exchange.

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]

Comments

0

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

Comments

0
# 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']]

Comments

-2

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

Comments

-3
    #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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.