Search

Python 2차원 배열 회전

Intro

2차원 배열을 회전시켜야 하는 일이 종종 있습니다.
좌표를 이용해서 2차원 배열을 회전시키는 방법도 있지만(아래), 행렬의 성질을 이용해서 쉽게 2차원 배열을 회전하는 방법을 소개하겠습니다.

좌표를 이용한 2차원 배열 회전

# 반시계방향 90도 회전 new_x = (n-1) - old_y new_y = old_x # 시계방향 90도 회전 new_x = old_y new_y = (n-1) - old_x
Python
복사

TL;DL

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

Explanation

다음과 같은 2차원 배열이 있다고 하겠습니다:
original = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Python
복사
위의 배열을 3X3 행렬처럼 다시 표현하면 다음과 같습니다:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Python
복사
배열을 역순으로 바꿉니다:
reversed_ = original[::-1] # reversed_ [[7, 8, 9], [4, 5, 6], [1, 2, 3]]
Python
복사
2차원 배열의 인자를 argument unpacking을 이용해 zip()으로 묶어줍니다.
zip()은 각 인자들을 tuple로 묶어 zip object로 반환하기 때문에 list()를 이용해 데이터 타입을 다시 바꿔줍니다:
rotated = list(zip(*reversed_)) # rotated [(7, 4, 1), (8, 5, 2), (9, 6, 3)]
Python
복사
다시 3X3 행렬 형태로 나타내서 비교해보면, 시계 방향으로 90도 회전한 것을 확인할 수 있습니다.
# original [[1, 2, 3], [4, 5, 6], [7, 8, 9]] # rotated [(7, 4, 1), (8, 5, 2), (9, 6, 3)]
Python
복사

Caveats

자세히보면 회전된 2차원 배열의 내부 값들이 tuple로 묶여 있기 때문에 회전 전후의 데이터 타입이 다릅니다.
따라서 tuple과 list의 성질을 이해한 상태에서 위의 테크닉을 사용해야 합니다.
tuple과 list 모두 요소들의 순서를 보장하기 때문에 회전 후에 for문 순회 등의 작업에는 무리가 없습니다.
하지만 list는 mutable한 반면, tuple은 immutable 하기 때문에 이를 명심합시다.

solution

다음과 같이 직접 구현하면 데이터 타입을 유지할 수 있습니다:
>> original = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] >> [[row[i] for row in original[::-1]] for i in range(len(original[0]))] [[7, 4, 1], [8, 5, 2], [9, 6, 3]]
Python
복사

Extra

1. Non-square Matrix

정방형이 아닌 행렬도 사용할 수 있습니다.
original = [[1, 2], [3, 4], [5, 6]] rotated = list(zip(*original[::-1])) # rotated [(5, 3, 1), (6, 4, 2)]
Python
복사
n x m 행렬은 m x n 행렬로 변합니다.

2. Transposition(전치)

회전이 아닌 전치를 해주고 싶다면 역순으로 바꾸지 않고 zip()을 해주면 됩니다:
>> original = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] >> list(zip(*original)) [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
Python
복사

Reference