1

Say I have:

a = [[1, 1, 1, 6], [0, 2, -1, 3], [4, 0, 10, 42]]

and I want to transpose it to:

a = [[1,0,4], [1,2,0], [1,-1,10], [6,3,42]]

using loops in python. The current code that I have is:

def transpose(a):
    s = []
    for row in range(len(a)):
        for col in range(len(a)):
            s = s + [a[col][row]]
return s

But this gives me the output of:

[1, 0, 4, 1, 2, 0, 1, -1, 10]

Instead of this:

[[1,0,4], [1,2,0], [1,-1,10], [6,3,42]]

Can anyone help me? I'm still new at this stuff and don't understand why it doesn't work. Thanks so much!

John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
Catury
  • 61
  • 2
  • 4

3 Answers3

1

Use zip()

>>> a = [[1, 1, 1, 6], [0, 2, -1, 3], [4, 0, 10, 42]]
>>> [list(x) for x in zip(*a)]
[[1, 0, 4], [1, 2, 0], [1, -1, 10], [6, 3, 42]]

zip(*a) unpacks the three sub-lists in a and combines them element by element. Meaning, the first elements of the each of the three sub-lists are combined together, the second elements are combined together and so on. But zip() returns tuples instead of lists like you want in your output. Like this:

>>> zip(*a)
[(1, 0, 4), (1, 2, 0), (1, -1, 10), (6, 3, 42)]

[list(x) for x in zip(*a)] converts each of the tuples to lists giving the output the way you need it.

shaktimaan
  • 11,962
  • 2
  • 29
  • 33
  • I know that's one way to do it, but is there another way to do this using for loops or while loops? – Catury Nov 05 '16 at 20:22
  • The other answer addresses your question. You are seeing one list in your output because you aren't creating a list in the inner loop. – shaktimaan Nov 05 '16 at 20:33
1

Here is a solution that is based on your code:

def transpose(a):
    s = []
    # We need to assume that each inner list has the same size for this to work
    size = len(a[0])
    for col in range(size):
        inner = []
        for row in range(len(a)):
            inner.append(a[row][col])
        s.append(inner)
    return s

If you define an inner list for the inner loop, your output is this:

[[1, 0, 4], [1, 2, 0], [1, -1, 10], [6, 3, 42]]
Maurice
  • 11,482
  • 2
  • 25
  • 45
  • Instead of inner.append and s.append, inner = inner + [a[row][col]] and s = s + [inner] works the same way! Thank you!! – Catury Nov 05 '16 at 20:44
  • I wouldn't say that it works *exactly* the same way - you might want to have a look at [this](https://stackoverflow.com/questions/2022031/python-append-vs-operator-on-lists-why-do-these-give-different-results/2022044#2022044) helpful answer that explains the differences. – Maurice Nov 05 '16 at 20:59
  • @Catury: It does not work the same way. When you do `list = list + [l]`, it creates a new list with the value of `list` and `l`, and assign new list to `list`. where as `list.append(l)` appends `l` to existing `list` list – Moinuddin Quadri Nov 05 '16 at 21:06
0

If you are looking for a solution without any fancy function. You may achieve it using list comprehension as:

>>> a = [[1, 1, 1, 6], [0, 2, -1, 3], [4, 0, 10, 42]]
>>> sublist_size = len(a[0])
>>> [[item[i] for item in a] for i in range(sublist_size)]
[[1, 0, 4], [1, 2, 0], [1, -1, 10], [6, 3, 42]]

However, simplest way is by using zip():

>>> list(zip(*a))  # for Python 3, OR, just zip(*a) in Python 2 
[(1, 0, 4), (1, 2, 0), (1, -1, 10), (6, 3, 42)]
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
  • Slightly shorter b = [[i[j] for i in a] for j in range(len(a)+1)] – JackTheCrab Nov 05 '16 at 20:43
  • 1
    @JackTheCrab: It is not necessary that sublist's length will be 1 more that the list's length (even though in this example). So `range(len(a[0]))` should be used instead of `range(len(a) + 1)`. By nesting the two steps and shortening the variable name to decrease one line of code; It is not good practice. Shorter is not always good. If bigger (to very little extent) code is more readable, go for bigger ;) – Moinuddin Quadri Nov 05 '16 at 20:49
  • You're right, thanks for pointing it out. Definetely agree on readability as well;) – JackTheCrab Nov 05 '16 at 20:53