在Python中旋转二维数组

pal*_*ind 104 python multidimensional-array

在一个程序中,我写的是需要旋转一个二维数组.寻找最佳解决方案我找到了这个令人印象深刻的单线工作:

rotated = zip(*original[::-1])
Run Code Online (Sandbox Code Playgroud)

我现在正在我的程序中使用它,它可以正常运行.我的问题是,我不明白它是如何工作的.

如果有人能解释所涉及的不同功能如何达到预期效果,我将不胜感激.

kin*_*all 83

这是一个聪明的一点.这是细分:

  • [::-1] - 以相反的顺序生成原始列表的浅表副本.也可以使用reversed()哪个会在列表上生成反向迭代器,而不是实际复制列表(更高的内存效率).
  • *- 使原始列表中的每个子列表成为一个单独的参数zip()(即,解压缩列表)
  • zip() - 从每个参数中获取一个项目并从中创建一个列表(好,一个元组),并重复直到所有子列表都用完为止.这是换位实际发生的地方.

所以假设你有这个:

[ [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9] ]
Run Code Online (Sandbox Code Playgroud)

你首先得到这个(浅,反向副本):

[ [7, 8, 9],
  [4, 5, 6],
  [1, 2, 3] ]
Run Code Online (Sandbox Code Playgroud)

接下来,每个子列表都作为参数传递给zip:

zip([7, 8, 9], [4, 5, 6], [1, 2, 3])
Run Code Online (Sandbox Code Playgroud)

zip() 从每个参数的开头重复使用一个项目,并从中生成一个元组,直到没有更多的项目,导致:

[(7, 4, 1), 
 (8, 5, 2), 
 (9, 6, 3)]
Run Code Online (Sandbox Code Playgroud)

而鲍勃是你的叔叔.

要在关于向另一个方向旋转它的评论中回答@ IkeMiguel的问题,它非常简单:你只需要反转进入的序列zip和结果.第一个可以通过移除来实现,[::-1]第二个可以通过抛出reversed()整个东西来实现.由于reversed()回报率在列表上的迭代器,我们需要把list()周围将其转换.所以:

rotated = list(zip(*reversed(original)))
Run Code Online (Sandbox Code Playgroud)

当然,您也可以简单地顺时针旋转列表三次.:-)

  • 可以逆时针旋转吗?? (2认同)
  • @MiguelIke 是的,做 zip(*matrix)[::-1] (2认同)
  • ^请注意,您必须将zip的结果转换为Python 3.x中的列表! (2认同)

And*_*ark 80

考虑以下二维列表:

original = [[1, 2],
            [3, 4]]
Run Code Online (Sandbox Code Playgroud)

让我们一步一步地分解它:

>>> original[::-1]   # elements of original are reversed
[[3, 4], [1, 2]]
Run Code Online (Sandbox Code Playgroud)

此列表将传递给zip()使用参数解包,因此zip调用最终将等效于此:

zip([3, 4],
    [1, 2])
#    ^  ^----column 2
#    |-------column 1
# returns [(3, 1), (4, 2)], which is a original rotated clockwise
Run Code Online (Sandbox Code Playgroud)

希望评论清楚地说明了什么zip,它将根据索引对每个输入可迭代的元素进行分组,或者换句话说,它将列分组.

  • 一个接近的。但是由于整洁的 ASCII 艺术,我选择了你的 ;) (3认同)
  • 和星号?? (2认同)

小智 16

这有三个部分:

  1. original [:: - 1]反转原始数组.这种表示法是Python列表切片.这为您提供了[start:end:step]描述的原始列表的"子列表",start是第一个元素,end是子列表中使用的最后一个元素.step说从头到尾采取每一步的元素.省略的开始和结束意味着切片将是整个列表,而否定步骤意味着您将获得相反的元素.所以,例如,如果原始是[x,y,z],结果将是[z,y,x]
  2. *在函数调用的参数列表中的列表/元组之前的*表示"扩展"列表/元组,以使其每个元素成为函数的单独参数,而不是列表/元组本身.因此,如果args = [1,2,3],则zip(args)与zip([1,2,3])相同,但zip(*args)与zip(1)相同2,3).
  3. zip是一个函数,它接受n个参数,每个参数的长度为m,并产生一个长度为m的列表,长度为n的元素包含每个原始列表的相应元素.例如,zip([1,2],[a,b],[x,y])是[[1,a,x],[2,b,y]].另见Python文档.


Mar*_*rkS 8

只是一个观察.输入是一个列表列表,但非常好的解决方案的输出:rotate = zip(*original [:: - 1])返回一个元组列表.

这可能是也可能不是问题.

但是,它很容易纠正:

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]]
Run Code Online (Sandbox Code Playgroud)

列表comp或地图都将内部元组转换回列表.