programing

Python에서 2차원 배열 회전

magicmemo 2023. 7. 15. 10:01
반응형

Python에서 2차원 배열 회전

제가 쓰고 있는 프로그램에서 2차원 배열을 회전시켜야 할 필요성이 제기되었습니다.최적의 솔루션을 찾다가 이 작업을 수행하는 인상적인 단일 라이너를 발견했습니다.

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

지금 프로그램에서 사용하고 있는데 예상대로 작동합니다.하지만 제 문제는 그것이 어떻게 작동하는지 이해할 수 없다는 것입니다.

관련된 다양한 기능들이 어떻게 원하는 결과를 얻을 수 있는지 누군가 설명해주시면 감사하겠습니다.

그것은 영리한 부분입니다.

한 것처럼 에서, 에에언것, Python 3에서.zip()를 복기를반전에포합야니함으로 .list()실제 목록을 다시 가져오려면 2020년 기준으로 다음과 같습니다.

list(zip(*original[::-1]))

내역은 다음과 같습니다.

  • [::-1]원래 목록의 복사본을 역순으로 만듭니다.사용할 수도 있습니다.reversed()이는 목록을 실제로 복사하는 것보다 목록 위에 역방향 반복기를 생성합니다(메모리 효율성이 더 높음).
  • *각을 원본 목록 목을에 대별인 만듭로다니수도에 대한 .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)]

밥은 네 삼촌이고

시키는 것에 대한 . @IkeMiguel에 두 뒤집으면 .zip그리고 그 결과.첫 번째는 다음을 제거함으로써 달성할 수 있습니다.[::-1]그리고 두 번째는 던짐으로써 달성될 수 있습니다.reversed()전체적으로부터reversed()합니다. 이 에는 목록위반반환합다니를기를 넣어야 . 우리는 입력해야 합니다.list()그것을 변환하기 위해 그 주변에.몇 개의 여분으로.list()반복자를 실제 목록으로 변환하는 호출입니다.그래서:

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

는 우는 " 션마스일마리를사스그수있용다여습니단조순할것금"가 아닌 " 더 할 수 .reversed()그러면 우리는 외부가 필요하지 않습니다.list():

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

물론 목록을 시계 방향으로 세 번만 돌리면 됩니다. :-)

다음의 2차원 목록을 고려해 보십시오.

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

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

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

은 이목은다전다니달됩으로 전달됩니다.zip()인수 분해를 사용하여, 그래서.zip호출은 결국 다음과 같습니다.

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

그 댓글들이 무엇을 명확히 하기를 바랍니다.zip인덱스를 기준으로 각 입력 테이블의 요소를 그룹화하거나, 즉 열을 그룹화합니다.

여기에는 세 부분이 있습니다.

  1. original[::-1]은(는) 원래 배열을 반대로 만듭니다.이 표기법은 파이썬 목록 슬라이싱입니다.이렇게 하면 [start:end:step]에 설명된 원래 목록의 "하위 목록"이 제공됩니다. 시작은 첫 번째 요소이고 끝은 하위 목록에서 사용할 마지막 요소입니다.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은 각각 길이가 m인 인수를 취하고 길이가 m인 목록을 생성하며 요소는 길이가 n이고 각 원래 목록의 해당 요소를 포함하는 함수입니다.예를 들어 zip([1,2], [a,b], [x,y])은 [1,a,x], [2,b,y]입니다.Python 설명서도 참조하십시오.

그냥 관찰일 뿐입니다.입력은 목록 목록이지만 매우 좋은 솔루션인 회전 = 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]]

리스트 컴퍼레이션 또는 맵은 둘 다 내부 튜플을 리스트로 다시 변환합니다.

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]

저 자신도 이 문제를 겪었고 그 주제에 대한 훌륭한 위키백과 페이지를 발견했습니다("공통 회전" 단락:
https://en.wikipedia.org/wiki/Rotation_matrix#://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 "=== === === === === === === === === "

시계 반대 방향으로 회전(표준 열에서 행 피벗으로) 목록 및 딕트로

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

매트릭스 시계 방향 회전:

mat = [[1,2,3],[4,5,6],[7,8,9]]
clock_rotated_mat = list(zip(*mat[::-1]))

# [(7, 4, 1), (8, 5, 2), (9, 6, 3)]

[::-1] - 행렬의 역행렬

zip(_) - 인덱스에 따라 각 목록의 중첩된 목록 값을 압축 해제합니다.

list() - 목록 개체로 다시 캐스트합니다.

마찬가지로 행렬 반시계방향 회전:

mat = [[1,2,3],[4,5,6],[7,8,9]]
anti_clock_rotated_mat = list(zip(*mat))[::-1]

# [(3, 6, 9), (2, 5, 8), (1, 4, 7)]

보다 단순한 하나의 라이너는 다음과 같습니다.

new_matrix = [list(row) for row in zip(*matrix)]

또는

new_matrix = list()
for row in zip(*matrix):
    new_matrix.append(list(row))

주요 부분은 각 반복 시 함수 인수로 전달되는 반복 가능 변수에서 하나의 요소가 있는 반복 가능 개체를 반환하는 zip 내장 함수를 사용하는 것입니다.리스트 a와 b를 넘겨 zip을 하고 던지기를 반복합니다.

a = [1, 2, 3]
b = [4, 5, 6]
for t in zip(a, b):
    print(t) # Print (1, 4) at the 1-st iteration, (2, 5) - 2nd,
             # and (3, 6) at the end.

또 다른 부분은 요소를 수동으로 전달하는 대신 언팩 작업(*)을 사용하는 것입니다.위의 변수를 목록으로 포장한 다음 zip 기능으로 압축을 풀 수 있습니다.

a = [1, 2, 3]
b = [4, 5, 6]
pack = [a, b]
for t in zip(*pack):
    print(t)

포장 풀기에 대한 자세한 내용은 문서를 참조하십시오.

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

반응형