问题:在Python中旋转二维数组
在一个程序中,我正在编写旋转二维数组的需求。在寻找最佳解决方案时,我发现了这种令人印象深刻的一线功能:
rotated = zip(*original[::-1])
我现在在程序中使用它,它按预期工作。我的问题是,我不了解它是如何工作的。
如果有人可以解释所涉及的不同功能如何实现所需的结果,我将不胜感激。
回答 0
考虑以下二维列表:
original = [[1, 2],
[3, 4]]
让我们将其逐步分解:
>>> original[::-1] # elements of original are reversed
[[3, 4], [1, 2]]
此列表传递给zip()
使用参数unpacking,因此zip
调用最终等效于此:
zip([3, 4],
[1, 2])
# ^ ^----column 2
# |-------column 1
# returns [(3, 1), (4, 2)], which is a original rotated clockwise
希望注释能够清楚说明其zip
作用,它将基于索引将来自每个可迭代输入的元素进行分组,或者换句话说,将列进行分组。
回答 1
太聪明了。
首先,如注释中所述,在Python 3中zip()
返回一个迭代器,因此您需要将整个内容封装起来list()
以得到实际的列表,因此从2020年开始实际上是:
list(zip(*original[::-1]))
这是细分:
[::-1]
-以相反的顺序对原始列表进行浅表复制。也可以使用reversed()
which来在列表上生成反向迭代器,而不是实际复制列表(更节省内存)。*
-使原始列表中的每个子列表成为一个单独的参数zip()
(即,解压缩列表)zip()
-从每个参数中取出一个项目,并从中得到一个列表(以及一个元组),然后重复进行直到所有子列表都用尽。这是换位实际发生的地方。list()
将的输出转换zip()
为列表。
所以假设你有这个:
[ [1, 2, 3],
[4, 5, 6],
[7, 8, 9] ]
您首先得到以下内容(浅色,反向副本):
[ [7, 8, 9],
[4, 5, 6],
[1, 2, 3] ]
接下来,每个子列表作为参数传递给zip
:
zip([7, 8, 9], [4, 5, 6], [1, 2, 3])
zip()
从其每个参数的开头重复消耗一个项目,并根据它生成一个元组,直到没有更多项目为止,结果是(将其转换为列表之后):
[(7, 4, 1),
(8, 5, 2),
(9, 6, 3)]
而鲍勃是你的叔叔。
要在有关将IkMiguel朝另一个方向旋转的评论中回答@IkeMiguel的问题,这非常简单:您只需要反转进入的序列zip
和结果。第一个可以通过删除来实现,[::-1]
第二个可以通过将reversed()
整个对象扔掉来实现。由于reversed()
回报率在列表上的迭代器,我们需要把list()
周围那将其转换。通过几次额外的list()
调用将迭代器转换为实际列表。所以:
rotated = list(reversed(list(zip(*original))))
我们可以使用“火星人的笑脸”切片而不是reversed()
… 来简化一点,那么我们不需要外部的list()
:
rotated = list(zip(*original))[::-1]
当然,您也可以简单地将列表顺时针旋转三下。:-)
回答 2
这包括三个部分:
- original [::-1]反转原始数组。该表示法是Python列表切片。这为您提供了[start:end:step]描述的原始列表的“子列表”,start是要在子列表中使用的第一个元素,end是最后一个要使用的元素。步骤说从头到尾走每一步。省略开始和结束意味着切片将是整个列表,而否定步骤意味着您将获得相反的元素。因此,例如,如果原始值为[x,y,z],则结果将为[z,y,x]
- *在函数调用的参数列表中的列表/元组前面时,*表示“扩展”列表/元组,以便其每个元素成为函数的单独参数,而不是列表/元组本身。因此,如果args = [1,2,3],则zip(args)与zip([1,2,3])相同,但是zip(* args)与zip(1, 2,3)。
- zip是一个函数,它接受n个参数,每个参数的长度为m,并生成一个长度为m的列表,其中的元素的长度为n,并包含每个原始列表的对应元素。例如,zip([1,2 ,, [a,b],[x,y])是[[1,a,x],[2,b,y]]。另请参阅Python文档。
回答 3
只是一个观察。输入是一个列表列表,但是非常好的解决方案的输出:旋转= 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]]
list comp或map都将内部元组转换回list。
回答 4
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]
回答 5
我自己遇到了这个问题,并且找到了关于该主题的出色维基百科页面(在“常见轮换”段落中:
https //en.wikipedia.org/wiki/Rotation_matrix#Ambiguities
然后,我编写了以下超级冗长的代码,以便对发生的事情有一个清晰的了解。
我希望您会发现在您发布的非常漂亮和聪明的单线中进行更多挖掘很有用。
要快速测试它,您可以在此处复制/粘贴它: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 "=== === === === === === === === === "
回答 6
逆时针旋转(标准列到行枢轴)作为列表和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]))
生成:
[['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]}