这段代码如何旋转矩阵?

8

在寻找一种用Python旋转矩阵的方法时,我看到了这篇答案。但是它没有解释。我在此复制代码段:

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

它是如何工作的?
3个回答

5
>>> lis = [[1,2,3], [4,5,6], [7,8,9]]

[::-1] 可以将列表反转:

>>> rev = lis[::-1]
>>> rev
[[7, 8, 9], [4, 5, 6], [1, 2, 3]]

现在我们对rev的所有项目使用zip,并将每个返回的元组追加到rotated中:

>>> rotated = []
>>> for item in zip(rev[0],rev[1],rev[2]):
...     rotated.append(item)
...     
>>> rotated
[(7, 4, 1), (8, 5, 2), (9, 6, 3)]

zip 会从传递给它的每个 iterable 中选取相同索引的项目(仅运行到最小长度项),并将它们作为元组返回。

那么 * 是什么:

* 用于将 rev 的所有项目解包到 zip 中,因此我们可以简单地使用 zip(*rev) 而不是手动输入 rev[0]、rev[1]、rev[2]

上面的 zip 循环也可以写成:

>>> rev = [[7, 8, 9], [4, 5, 6], [1, 2, 3]]
>>> min_length = min(len(x) for x in rev)  # find the min length among all items
>>> rotated = []

for i in xrange(min_length):        
    items = tuple(x[i] for x in rev)  # collect items on the same index from each
                                      # list inside `rev`  
    rotated.append(items)
...     
>>> rotated
[(7, 4, 1), (8, 5, 2), (9, 6, 3)]

5

在Ashwini和HennyH的解释之外,这里有一个小图来说明该过程。

enter image description here

  1. 首先,[::-1] 切片操作符将列表的列表反转,取整个列表(因此可以省略前两个参数)并使用步长为 -1
  2. 其次,zip 函数接受多个列表,并有效地返回一个新的列表,行和列被颠倒。 * 表示要将列表的列表展开为多个列表。

如图所示,这两个操作结合起来将旋转矩阵。


2

为了我的解释:

>>> m = [['a','b','c'],[1,2,3]]

如果进行漂亮的打印,它将是这样的:

>>> pprint(m)
['a', 'b', 'c']
[1, 2, 3]

首先,zip(*m)会创建一个包含m中所有的列表。如下所示:

>>> zip(*m)
[('a', 1), ('b', 2), ('c', 3)]

这是如何运作的: zip 接受 n 个序列,并获取每个序列的第 i 个元素并将其添加到一个元组中。因此,将其转换为我们的矩阵 m,其中每个 由包含在 m 中的列表表示,我们基本上将每一行传递给 zip,然后从每行中获取第一个元素并将所有这些元素放入一个元组中,然后从每行中获取每个第二个元素等等... 最终获得 m 中的每个 ,即:
>>> zip(['row1column1','row1column2'],['row2column1','row2column2'])
[('row1column1', 'row2column1'), ('row1column2', 'row2column2')]
Notice that each tuple contains all the elements in a specific column

现在它看起来像这样:
>>> pprint(zip(*m))
('a', 1)
('b', 2)
('c', 3)

因此,实际上,m 中的每个 现在都是一行。然而它们的顺序不正确(试着想象一下在头脑中旋转 m 以获取上面的矩阵,这是不可能的)。这就是为什么需要“翻转”原始矩阵的原因:
>>> pprint(zip(*m[::-1]))
(1, 'a')
(2, 'b')
(3, 'c')

这将导致一个矩阵,其等效于将m逆时针旋转90度。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接