-->

How to I invert a 2d list in python [duplicate]

2019-04-10 17:35发布

问题:

This question already has an answer here:

  • Transpose list of lists 10 answers

I have a 2d list like this:

   1   2   3

   4   5   6

and I want to make this:

   1   4

   2   5

   3   6

I've tried to do a for loop and switch each value but I keep getting an index out of bound error. Here's what I have:

for i in results:
    for j in range(numCenturies):
        rotated[i][j] = results [j][i]

回答1:

From python documentation on zip function:

This function returns a list of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. The returned list is truncated in length to the length of the shortest argument sequence. When there are multiple arguments which are all of the same length, zip() is similar to map() with an initial argument of None. With a single sequence argument, it returns a list of 1-tuples. With no arguments, it returns an empty list.

Example:

zip([1, 2, 3], [4, 5, 6]) # returns [(1, 4), (2, 5), (3, 6)]

If you need the result to be the list of lists, not the list of tuples, you can use list comprehension:

[list(x) for x  in zip([1, 2, 3], [4, 5, 6], [7, 8, 9])] # returns [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

If all your variables are stored in one 2d list, and you want it pass it into zip function, you can use the following (I'll call it the star notation, because I can't remember the proper English term for it):

results = [[1, 2, 3], [4, 5, 6]]
zip(*results) # returns [(1, 4), (2, 5), (3, 6)]


回答2:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html

>>> from numpy import transpose
>>> transpose([[1,2,3],[4,5,6]])
array([[1, 4],
       [2, 5],
       [3, 6]])


回答3:

zip is the right way to do this, as shown by aga.

But if you want to know why your original code wasn't working:

for i in results:
    for j in range(numCenturies):
        rotated[i][j] = results [j][i]

There are two clear problems here, and likely two others. (Since you didn't show us enough of the code or data to be sure, I can't guarantee the two likely ones.)

Presumably results looks something like this:

results = [[1, 2, 3], [4, 5, 6]]

When you do for i in results, that means i will be each element in results—that is, it will be [1, 2, 3], and then [4, 5, 6]. You can't use a list as an index into a list, so this is guaranteed to give you a TypeError: list indices must be integers, not list.

To fix this, you need:

for i in range(len(results)):

… or …

for i, row in enumerate(results):

Next, results[j][i] is guaranteed to raise IndexError: list index out of range, because i is each row number, but you're trying to use it as a column number. If you're iterating over the rows and columns of results, you want this:

rotated[j][i] = results[i][j]

Next, unless you pre-filled rotated with 3 lists, each of which was pre-filled with 2 objects of some kind, you're going to get an IndexError: list assignment index out of range.

To fix this, you need to pre-fill rotated, something like this:

rotated = [[None for j in range(2)] for i in range(3)]

… or …

rotated = [[None, None], [None, None], [None, None]]

Finally, I'll bet numCenturies is 3, in which case you'll get another IndexError: list index out of range as soon as j reaches 2. The simplest thing to do here is to just use the length of the row; there's no chance of an off-by-one error that way.

Putting it all together:

rotated = [[None for j in range(2)] for i in range(3)]
for i, row in enumerate(results):
    for j, value in enumerate(row):
        rotated[j][i] = value

But in general, Python gives you easier ways to do things than pre-creating arrays and looping over indices to fill in the values. You can use append—or, better, a list comprehension. Or, even better, find a higher-level way to write your use, like a single call to zip.