# Rotating a two-dimensional array in Python

## Question:

In a program I’m writing the need to rotate a two-dimensional array came up. Searching for the optimal solution I found this impressive one-liner that does the job:

```
rotated = zip(*original[::-1])
```

I’m using it in my program now and it works as supposed. My problem though, is that I don’t understand how it works.

I’d appreciate if someone could explain how the different functions involved achieves the desired result.

## Answers:

That’s a clever bit.

First, as noted in a comment, in Python 3 `zip()`

returns an iterator, so you need to enclose the whole thing in `list()`

to get an actual list back out, so as of 2020 it’s actually:

```
list(zip(*original[::-1]))
```

Here’s the breakdown:

`[::-1]`

– makes a shallow copy of the original list in reverse order. Could also use`reversed()`

which would produce a reverse iterator over the list rather than actually copying the list (more memory efficient).`*`

– makes each sublist in the original list a separate argument to`zip()`

(i.e., unpacks the list)`zip()`

– takes one item from each argument and makes a list (well, a tuple) from those, and repeats until all the sublists are exhausted. This is where the transposition actually happens.`list()`

converts the output of`zip()`

to a list.

So assuming you have this:

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

You first get this (shallow, reversed copy):

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

Next each of the sublists is passed as an argument to `zip`

:

```
zip([7, 8, 9], [4, 5, 6], [1, 2, 3])
```

`zip()`

repeatedly consumes one item from the beginning of each of its arguments and makes a tuple from it, until there are no more items, resulting in (after it’s converted to a list):

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

And Bob’s your uncle.

To answer @IkeMiguel’s question in a comment about rotating it in the other direction, it’s pretty straightforward: you just need to reverse both the sequences that go into `zip`

and the result. The first can be achieved by removing the `[::-1]`

and the second can be achieved by throwing a `reversed()`

around the whole thing. Since `reversed()`

returns an iterator over the list, we will need to put `list()`

around *that* to convert it. With a couple extra `list()`

calls to convert the iterators to an actual list. So:

```
rotated = list(reversed(list(zip(*original))))
```

We can simplify that a bit by using the "Martian smiley" slice rather than `reversed()`

… then we don’t need the outer `list()`

:

```
rotated = list(zip(*original))[::-1]
```

Of course, you could also simply rotate the list clockwise three times. ðŸ™‚

Consider the following two-dimensional list:

```
original = [[1, 2],
[3, 4]]
```

Lets break it down step by step:

```
>>> original[::-1] # elements of original are reversed
[[3, 4], [1, 2]]
```

This list is passed into `zip()`

using argument unpacking, so the `zip`

call ends up being the equivalent of this:

```
zip([3, 4],
[1, 2])
# ^ ^----column 2
# |-------column 1
# returns [(3, 1), (4, 2)], which is a original rotated clockwise
```

Hopefully the comments make it clear what `zip`

does, it will group elements from each input iterable based on index, or in other words it groups the columns.

There are three parts to this:

- original[::-1] reverses the original array. This notation is Python list slicing. This gives you a “sublist” of the original list described by [start:end:step], start is the first element, end is the last element to be used in the sublist. step says take every step’th element from first to last. Omitted start and end means the slice will be the entire list, and the negative step means that you’ll get the elements in reverse. So, for example, if original was [x,y,z], the result would be [z,y,x]
- The * when preceding a list/tuple in the argument list of a function call means “expand” the list/tuple so that each of its elements becomes a separate argument to the function, rather than the list/tuple itself. So that if, say, args = [1,2,3], then zip(args) is the same as zip([1,2,3]), but zip(*args) is the same as zip(1,2,3).
- zip is a function that takes n arguments each of which is of length m and produces a list of length m, the elements of are of length n and contain the corresponding elements of each of the original lists. E.g., zip([1,2],[a,b],[x,y]) is [[1,a,x],[2,b,y]]. See also Python documentation.

I’ve had this problem myself and I’ve found the great wikipedia page on the subject (in “Common rotations” paragraph:

https://en.wikipedia.org/wiki/Rotation_matrix#Ambiguities

Then I wrote the following code, super verbose in order to have a clear understanding of what is going on.

I hope that you’ll find it useful to dig more in the very beautiful and clever one-liner you’ve posted.

To quickly test it you can copy / paste it here:

http://www.codeskulptor.org/

```
triangle = [[0,0],[5,0],[5,2]]
coordinates_a = triangle[0]
coordinates_b = triangle[1]
coordinates_c = triangle[2]
def rotate90ccw(coordinates):
print "Start coordinates:"
print coordinates
old_x = coordinates[0]
old_y = coordinates[1]
# Here we apply the matrix coming from Wikipedia
# for 90 ccw it looks like:
# 0,-1
# 1,0
# What does this mean?
#
# Basically this is how the calculation of the new_x and new_y is happening:
# new_x = (0)(old_x)+(-1)(old_y)
# new_y = (1)(old_x)+(0)(old_y)
#
# If you check the lonely numbers between parenthesis the Wikipedia matrix's numbers
# finally start making sense.
# All the rest is standard formula, the same behaviour will apply to other rotations, just
# remember to use the other rotation matrix values available on Wiki for 180ccw and 170ccw
new_x = -old_y
new_y = old_x
print "End coordinates:"
print [new_x, new_y]
def rotate180ccw(coordinates):
print "Start coordinates:"
print coordinates
old_x = coordinates[0]
old_y = coordinates[1]
new_x = -old_x
new_y = -old_y
print "End coordinates:"
print [new_x, new_y]
def rotate270ccw(coordinates):
print "Start coordinates:"
print coordinates
old_x = coordinates[0]
old_y = coordinates[1]
new_x = -old_x
new_y = -old_y
print "End coordinates:"
print [new_x, new_y]
print "Let's rotate point A 90 degrees ccw:"
rotate90ccw(coordinates_a)
print "Let's rotate point B 90 degrees ccw:"
rotate90ccw(coordinates_b)
print "Let's rotate point C 90 degrees ccw:"
rotate90ccw(coordinates_c)
print "=== === === === === === === === === "
print "Let's rotate point A 180 degrees ccw:"
rotate180ccw(coordinates_a)
print "Let's rotate point B 180 degrees ccw:"
rotate180ccw(coordinates_b)
print "Let's rotate point C 180 degrees ccw:"
rotate180ccw(coordinates_c)
print "=== === === === === === === === === "
print "Let's rotate point A 270 degrees ccw:"
rotate270ccw(coordinates_a)
print "Let's rotate point B 270 degrees ccw:"
rotate270ccw(coordinates_b)
print "Let's rotate point C 270 degrees ccw:"
rotate270ccw(coordinates_c)
print "=== === === === === === === === === "
```

Just an observation. The input is a list of lists, but the output from the very nice solution: rotated = zip(*original[::-1]) returns a list of tuples.

This may or may not be an issue.

It is, however, easily corrected:

```
original = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
def rotated(array_2d):
list_of_tuples = zip(*array_2d[::-1])
return [list(elem) for elem in list_of_tuples]
# return map(list, list_of_tuples)
print(list(rotated(original)))
# [[7, 4, 1], [8, 5, 2], [9, 6, 3]]
```

The list comp or the map will both convert the interior tuples back to lists.

```
def ruota_orario(matrix):
ruota=list(zip(*reversed(matrix)))
return[list(elemento) for elemento in ruota]
def ruota_antiorario(matrix):
ruota=list(zip(*reversed(matrix)))
return[list(elemento)[::-1] for elemento in ruota][::-1]
```

Rotating Counter Clockwise ( standard column to row pivot ) As List and Dict

```
rows = [
['A', 'B', 'C', 'D'],
[1,2,3,4],
[1,2,3],
[1,2],
[1],
]
pivot = []
for row in rows:
for column, cell in enumerate(row):
if len(pivot) == column: pivot.append([])
pivot[column].append(cell)
print(rows)
print(pivot)
print(dict([(row[0], row[1:]) for row in pivot]))
```

Produces:

```
[['A', 'B', 'C', 'D'], [1, 2, 3, 4], [1, 2, 3], [1, 2], [1]]
[['A', 1, 1, 1, 1], ['B', 2, 2, 2], ['C', 3, 3], ['D', 4]]
{'A': [1, 1, 1, 1], 'B': [2, 2, 2], 'C': [3, 3], 'D': [4]}
```

matrix clockwise rotation:

```
mat = [[1,2,3],[4,5,6],[7,8,9]]
clock_rotated_mat = list(zip(*mat[::-1]))
# [(7, 4, 1), (8, 5, 2), (9, 6, 3)]
```

[::-1] – reverse the matrix

zip(*_) – unpacks the nested list values of each list according to its index.

list() – cast back to list object.

similarly, matrix anti-clockwise rotation:

```
mat = [[1,2,3],[4,5,6],[7,8,9]]
anti_clock_rotated_mat = list(zip(*mat))[::-1]
# [(3, 6, 9), (2, 5, 8), (1, 4, 7)]
```