[英]rotate Image List comprehension
在解决矩阵旋转问题时,我遇到了一个解决方案。问题是将矩阵旋转90度。
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)]
有人可以帮助我将列表理解分解为常规的for循环并了解程序的流程吗
您有一个嵌套列表理解,一个外部列表理解为每次迭代创建一个新列表。
您可以通过读取for
和if
组件从左到右作为嵌套块来解构任何列表理解。 第一个for
之前的所有内容都是产生列表元素的表达式。
因此,基本结构为:
[<expression> for <targets> in <iterable> <optionally more if and for>]
始终可以使用以下命令将其转换为常规循环:
_result = []
for <targets> in <iterable>:
<optionally more if and for blocks, add a new level each time>
_result.append(<expression>)
我添加了_result
作为所生成列表的显式名称。 请注意,每次迭代都会将<expression>
的结果附加到它的后面。
您的示例分为两个列表理解。 外循环是这样的:
[[m[i] for m in a] for i in range(cols)]
# \ / | \ /
# <expression> <targets> <iterable>
因此[m[i] for m in a]
是这里的表达式! 将其写为:
_result_outer = []
for i in range(cols):
_result_outer.append([m[i] for m in a])
内部列表的理解很简单:
_result_inner = []
for m in a:
_result_inner.append(m[i])
如果将这两部分放在一起,您将获得:
_result_outer = []
for i in range(cols):
_result_inner = []
for m in a:
_result_inner.append(m[i])
_result_outer.append(_result_inner)
现在您可以看到,每次在内部循环中都使用外部循环中的i
目标。 因为i
遍历了列数,但是m
是一行,所以这首先生成一个列表,其中包含第一列的所有值,然后是第二列,然后是第三列,依此类推。
列表理解之前的那一行使行反转 :
a = a[::-1]
这将占用所有行,并从最后一行到第一行(向后退,步长为-1
)。 这样可以使列表理解以相反的顺序遍历行。
该代码可以清理和改进一点。 例如,从不使用rows
变量,我们可以使用reversed()
函数以相反的顺序遍历列表,而无需创建副本:
def rotateImage(a):
cols = len(a[0])
return [[m[i] for m in reversed(a)] for i in range(cols)]
转换矩阵(将列移动到行)的另一种方法是使用zip()
函数,其中所有行都应用为单独的参数,并带有*<expression>
调用语法:
def rotateImage(a):
return [list(r) for r in zip(*reversed(a))]
这仍然使用列表推导,因为zip()
会生成一个可迭代的对象 ,而不是列表,并且每次迭代时都会得到一个元组。 上面的列表理解将整个结果转换回列表列表。
如果您想就地执行此操作,建议您阅读Jack关于用Python旋转矩阵的出色回答。 他们对如何编码的解释是首屈一指的: 如何旋转二维数组?
a=a[::-1]
只是一个反向。 列表理解为:
res = []
for i in range(cols):
tmp = []
for m in a:
tmp.append(m[i])
res.append(tmp)
return res
****编辑****
基本上,这里发生的是对于每个列索引i
,算法遍历所有行m
(从最后到第一),并将m[i]
(第m行中的第i个值)附加到tmp
,然后作为行附加到res
。 因此,每个反向列都作为一行添加到res
。
因此,对于像这样的矩阵:
1 2 3 4
5 6 7 8
9 1 0 4
第一次内部循环迭代将导致tmp=[9, 5, 1]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.