파이썬은 배열 회전은 zip을 이용하면 1줄에 끝내버릴 수 있습니다. 그 방법을 알아봅시다.


 3번째 줄이 90도 회전하는 소스입니다. c++로 구현할 때, 줄수가 꽤 길었는데요. 파이썬은 의외입니다? zip과 asterisk, 그리고 list 컴프리헨션으로 간단하게 구현할 수 있어요. 이 과정을 하나 하나 짚어보겠습니다. 먼저, zip(*li) 부터 보겠습니다. 이것에 대한 문법적인 설명은 다음에 언급하도록 하겠습니다. zip을 쓸 때 짝꿍처럼 많이 쓰이니, 이디엄처럼 외워 봅시다.

 

 

 

 

 문서를 보시면 li가 [1, 2, 3]일 때, f(*li)는 f(1, 2, 3)과 똑같습니다. 그러면, li가 [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]일 때, zip(*li)는 무엇과 같을까요? zip([1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12])와 같음을 어렵지 않게 알 수 있어요. 이제 zip은 4개의 인자를 받은 것입니다. 이제, 문제의 메서드를 보도록 하겠습니다.

 

[관련글]

python의 zip 메서드를 알아봅시다.

 

 제가 링크한 관련 글에 따르면, 병렬 iteration을 돌릴 때 유용하다고 하였는데요. 문서를 보면, while 루프 안에 yield가 나와요. yield가 있으면 해당 함수는 제너레이터가 되는데요. 이 메서드의 역할은, 단지 한 번 호출이 되면, 각 iterable한 것들의 다음 원소들을 탐색해서, 리스트에 넣게 되어요. 여기에서 들어온 것은 [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]였습니다.

 

 

 그러면 제너레이터는, iterable한 객체에서 1번째 원소들을 가지고 와서 tuple에 저장하고 리턴해 버립니다. (1, 4, 7, 10)을 리턴하고, 제너레이터는 freeze가 됩니다. 그러면 다시 제너레이터가 호출이 될 때, 그 다음 원소들을 리턴할 겁니다.

 

 (2, 5, 8, 11)이 다음 원소들이네요.

 

 다음에 제너레이터가 다시 호출되면 (3, 6, 9, 12)를 돌려줍니다. 여기서 (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)는 generator를 돌면서 리턴된 것들입니다. k in zip(*li)까지 설명이 되었네요. 이제 배열을 90도 시계 방향으로 회전하면 어떻게 되는지 생각해 봅시다.

 

 

 이게 시계 방향으로 90도만큼 회전한 결과물입니다. 1번째 원소는 (1, 4, 7, 10)을 뒤집은 것입니다. 2번째 원소는 (2, 5, 8, 10)을 뒤집은 것이고, 3번째 원소는 (3, 6, 9, 12)를 뒤집은 거에요. 따라서, k[::-1]로 reverse를 시킨 것입니다. 이것을 정리하면 아래와 같습니다.

 

 3번째 줄은 2차원 배열 li를 시계 방향으로 90도 회전시킵니다. 만약에, 반시계 방향으로 90도 회전시키려면 어떻게 하면 될까요? 이 일을 3번 반복하면 됩니다. 시계 방향으로 270도 회전한 것과, 반시계 방향으로 90도 회전한 것은 같기 때문이에요.

 

 실행 결과는 위와 같습니다.


 그런데 numpy를 이용해서 하는 방법도 있습니다. rot90을 이용하면 되는데요. 2차원 배열을 시계 방향으로 90도 회전시키기 위해서는, rot90의 2번째 인자에 3을 넣어주시면 되는데요. 이는, 반시계 방향으로 3번 회전시키겠다는 의미입니다.

 

 먼저 4번째 줄에서, list를 numpy array로 바꿉니다. 다음에, np.rot90(o, 3)을 한 결과를 list로 바꾸는 것이 5번째 줄입니다. numpy의 ndarray에 tolist 메서드가 있음을 보시면 됩니다. 6번째 줄에 li를 출력하는데요. 이는 시계 방향으로 90도 회전한 결과를 출력하겠다는 의미입니다.

 

 

 

 제대로 나왔는지 검증해 봅시다. 제대로 나왔는지 보려면, 1번 회전했을 때 2차원 배열의 원소가 [10, 7, 4, 1], [11, ... ], [12, ...] 순서대로 있는지 보면 됩니다. 그리고, 2번 회전했을 때, 2차원 배열에 [12, 11, 10], [9, 8, 7], [6, ...], [3, ...] 순서대로 있는지 보시면 됩니다. 그런지 볼까요?

 

 

 의도한 대로 나왔음을 알 수 있습니다. zip과 애스터리크, 그리고 list 컴프리헨션은 익혀 두시면 여러 구현 문제에서 쓰일 수 있으니 익혀두시면 좋겠습니다.