简体   繁体   中英

rotate Image List comprehension

While solving a problem on matrix rotation I came across a solution .The question asks to rotate the matrix by 90 degrees in place.

def rotateImage(a):
    rows = len(a)
    cols = len(a[0])
    a=a[::-1]
    return [[m[i] for m in  a] for i in range(cols)]

Can someone help me in breaking down this list comprehension to regular for-loop and understand the flow of the program

You have a nested list comprehension, an outer list comprehension creating a new list for every iteration.

You can deconstruct any list comprehension by reading the for and if components from left to right as nested blocks. Everything before the first for is the expression that produces the elements of the list.

So the basic structure is:

[<expression> for <targets> in <iterable> <optionally more if and for>]

which can always be converted to a regular loop with:

_result = []
for <targets> in <iterable>:
    <optionally more if and for blocks, add a new level each time>
        _result.append(<expression>)

I added in _result as an explicit name for the list that is produced; note that the result of <expression> is appended to it each iteration.

Your example breaks down to two list comprehensions. The outer loop is this:

[[m[i] for m in  a] for i in range(cols)]
# \              /      |     \       /
#   <expression>    <targets>  <iterable>

So the [m[i] for m in a] is the expression here! Writing this out that becomes:

_result_outer = []
for i in range(cols):
    _result_outer.append([m[i] for m in  a])

The inner list comprehension is straightforward:

_result_inner = []
for m in a:
    _result_inner.append(m[i])

If you put these two together you get:

_result_outer = []
for i in range(cols):
    _result_inner = []
    for m in a:
        _result_inner.append(m[i])
    _result_outer.append(_result_inner)

Now you can see that the i target from the outer loop, is used each time in the inner loop. Because i loops over the number of columns, but m is a row, this produces first a list with all the values from the very first column, then the second column, and then the third, etc.

The line before the list comprehension reversed the rows:

a = a[::-1]

This takes all rows, and goes from the last to the first (stepping backwards, with a -1 step size). This makes it so that the list comprehension loops over the rows in reverse order.

The code can be cleaned up and improved a little. The rows variable is never used, for example, and we can use the reversed() function to loop over a list in reverse order without creating a copy:

def rotateImage(a):
    cols = len(a[0])
    return [[m[i] for m in reversed(a)] for i in range(cols)]

Another method of transposing a matrix (moving columns to rows) is using the zip() function with all the rows applied as separate arguments, with the *<expression> call syntax:

def rotateImage(a):
    return [list(r) for r in zip(*reversed(a))]

This still uses a list comprehension, because zip() produces an iterable object , not a list, and each time you iterate you get a tuple. The above list comprehension converts the whole result back to a list of lists.

If you want to do this in place , I suggest you read the very excellent answer Jack wrote on rotating a matrix with Python; their explanation of how to code this is second to none: How do you rotate a two dimensional array?

The a=a[::-1] is simply a in reverse. The list comprehension is:

res = []
for i in range(cols):
    tmp = []
    for m in a:
        tmp.append(m[i])
    res.append(tmp)
return res

****EDIT****

What is basically happening here is the for each column index i the algorithm goes through all the rows m (form last to first) and appends the m[i] (the i'th value in the m'th row) to tmp , which is then appended as a row, to res . So each reversed column is added as a row to res .

So for a matrix like:

1 2 3 4
5 6 7 8
9 1 0 4

The first inner loop iteration will result in tmp=[9, 5, 1]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM