Programing

Python에서 2 차원 배열 회전

lottogame 2020. 8. 20. 19:25
반응형

Python에서 2 차원 배열 회전


프로그램에서 2 차원 배열을 회전 할 필요가 있다고 작성했습니다. 최적의 솔루션을 찾다가이 작업을 수행하는 인상적인 원 라이너를 찾았습니다.

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

지금 내 프로그램에서 사용하고 있으며 예상대로 작동합니다. 내 문제는 그것이 어떻게 작동하는지 이해하지 못한다는 것입니다.

누군가가 관련된 다른 기능이 원하는 결과를 얻는 방법을 설명 할 수 있다면 감사하겠습니다.


다음 2 차원 목록을 고려하십시오.

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

단계별로 분석해 보겠습니다.

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

이 목록은 unpacking 인수zip()사용하여 전달 되므로 호출은 다음과 동일하게됩니다.zip

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

주석이 무엇을하는지 명확하게 zip해주길 바라며, 인덱스를 기반으로 반복 가능한 각 입력의 요소를 그룹화하거나, 즉 열을 그룹화합니다.


영리한 부분입니다. 분석은 다음과 같습니다.

  • [::-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. original [::-1]은 원래 배열을 반대로합니다. 이 표기법은 Python 목록 슬라이싱입니다. 이렇게하면 [start : end : step]에 설명 된 원래 목록의 "하위 목록"이 제공됩니다. start는 첫 번째 요소이고 end는 하위 목록에서 사용할 마지막 요소입니다. 단계는 모든 단계의 요소를 처음부터 끝까지 가져 간다고 말합니다. 생략 된 시작과 끝은 슬라이스가 전체 목록이됨을 의미하고 음수 단계는 요소를 반대로 가져옴을 의미합니다. 예를 들어 원본이 [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 is a function that takes n arguments each of which is of length m and produces a list of length m, the elements of are of length n and contain the corresponding elements of each of the original lists. E.g., zip([1,2],[a,b],[x,y]) is [[1,a,x],[2,b,y]]. See also Python documentation.

Just an observation. The input is a list of lists, but the output from the very nice solution: rotated = zip(*original[::-1]) returns a list of tuples.

This may or may not be an issue.

It is, however, easily corrected:

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

The list comp or the map will both convert the interior tuples back to lists.


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]

I've had this problem myself and I've found the great wikipedia page on the subject (in "Common rotations" paragraph:
https://en.wikipedia.org/wiki/Rotation_matrix#Ambiguities

Then I wrote the following code, super verbose in order to have a clear understanding of what is going on.

I hope that you'll find it useful to dig more in the very beautiful and clever one-liner you've posted.

To quickly test it you can copy / paste it here:
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 "=== === === === === === === === === "

I was practicing python nested list comprehensions and coded the following to return a list of columns in a matrix, which is analogous to rotating the matrix:

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

참고URL : https://stackoverflow.com/questions/8421337/rotating-a-two-dimensional-array-in-python

반응형