在Python中旋转二维数组

时间:2011-12-07 19:31:31

标签: python multidimensional-array

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

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

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

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

8 个答案:

答案 0 :(得分:74)

这是一个聪明的位。这是细分:

  • [::-1] - 以相反的顺序制作原始列表的浅表副本。也可以使用reversed()来生成列表上的反向迭代器,而不是实际复制列表(更高效的内存)。
  • * - 使原始列表中的每个子列表成为zip()的单独参数(即,解压缩列表)
  • 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)]

鲍勃是你的叔叔。

要回答@ IkeMiguel关于在另一个方向上旋转它的问题的问题,它非常简单:你只需要反转进入zip的序列和结果。第一个可以通过删除[::-1]来实现,第二个可以通过在整个事件周围抛出reversed()来实现。由于reversed()会在列表中返回迭代器,因此我们需要将list()放在 周围进行转换。所以:

rotated = list(zip(*reversed(original)))

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

答案 1 :(得分:71)

考虑以下二维列表:

original = [[1, 2],
            [3, 4]]

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

>>> original[::-1]   # elements of original are reversed
[[3, 4], [1, 2]]

此列表使用argument unpacking传递到zip(),因此zip调用最终会相当于此:

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

希望评论明确zip的作用,它会根据索引对每个输入可迭代的元素进行分组,或者换句话说,它将列分组。

答案 2 :(得分:14)

这有三个部分:

  1. original [:: - 1]反转原始数组。这种表示法是Python列表切片。这为您提供了[start:end:step]描述的原始列表的“子列表”,start是第一个元素,end是子列表中使用的最后一个元素。 step说从头到尾采取每一步的元素。省略的开始和结束意味着切片将是整个列表,而否定步骤意味着您将获得相反的元素。所以,例如,如果original是[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 documentation.

答案 3 :(得分:7)

只是一个观察。输入是一个列表列表,但非常好的解决方案的输出:rotating = 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都会将内部元组转换回列表。

答案 4 :(得分:1)

我自己遇到过这个问题,我找到了关于这个主题的精彩维基百科页面(在“共同轮换”段落中: 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 "=== === === === === === === === === "

答案 5 :(得分:1)

def ruota_antiorario(matrix):
   ruota=list(zip(*reversed(matrix)))
   return[list(elemento) for elemento in ruota]
def ruota_orario(matrix):
   ruota=list(zip(*reversed(matrix)))
   return[list(elemento)[::-1] for elemento in ruota][::-1]

答案 6 :(得分:0)

逆时针旋转(标准列到行枢轴)为列表和字典

df_out = df_a.join([df_b], how='outer').reindex(index)

Out[1068]:
                     Temperature  Humidity  Pressure
2019-05-25 10:00:00         25.0      60.0       NaN
2019-05-25 10:05:00         26.0      25.0    1020.0
2019-05-25 10:10:00         27.0      63.0    1021.0
2019-05-25 10:15:00          NaN       NaN    1019.0
2019-05-25 10:20:00         28.0      62.0       NaN

产生:

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]))

答案 7 :(得分:-3)

我正在练习python嵌套列表推导并编写以下代码以返回矩阵中的列列表,这类似于旋转矩阵:

def getColumns(matrix):
  columns = [[row[col] for row in matrix] for col in range(len(matrix[1]))]
  return columns