리스트(List)는 파이썬에서 가장 중요한 컨테이너 자료형 중 하나로, 일상적인 프로그래밍은 물론 웹 개발에 이르기까지 거의 모든 코드에서 사용됩니다. 리스트를 자주 활용할수록 다양한 연산을 능숙하게 다루는 것이 필수적이며, 그중에서도 리스트 회전(Rotation)은 실무와 코딩 테스트에서 자주 등장하는 대표적인 연산입니다.
이 글에서는 파이썬에서 리스트를 왼쪽 또는 오른쪽으로 회전하는 세 가지 방법을 예제 코드와 함께 살펴봅니다. 각 방식의 특징을 이해하고 상황에 맞는 방법을 선택하는 데 도움이 되길 바랍니다.
1. 슬라이싱(Slicing)을 이용한 회전
가장 직관적이고 널리 쓰이는 방법입니다. 왼쪽으로 n칸 회전할 때는 앞의 n개 요소를 잘라 뒤에 붙이고, 오른쪽으로 n칸 회전할 때는 뒤의 n개 요소를 앞에 붙이면 됩니다. 아래 예제는 3칸씩 회전하며, 오른쪽으로 3칸 회전하면 다시 원래 상태로 돌아옵니다.
# 슬라이싱(slicing) 방식
# 리스트 초기화
test_list = [1, 4, 6, 7, 2]
# 원본 리스트 출력
print("Original list : " + str(test_list))
# 슬라이싱으로 왼쪽 3칸 회전
test_list = test_list[3:] + test_list[:3]
# 왼쪽 회전 결과 출력
print("List after left rotate by 3 : " + str(test_list))
# 슬라이싱으로 오른쪽 3칸 회전 (원상 복구)
test_list = test_list[-3:] + test_list[:-3]
# 오른쪽 회전 결과 출력
print("List after right rotate by 3(back to original) : " + str(test_list))동작 원리: test_list[3:]은 인덱스 3부터 끝까지, test_list[:3]은 처음부터 인덱스 2까지의 요소를 의미합니다. 두 조각의 순서를 바꿔 합치면 왼쪽 회전이 되고, 음수 인덱스(-3:)를 활용하면 반대 방향 회전도 간단히 구현됩니다.
2. 리스트 컴프리헨션(List Comprehension)을 이용한 회전
모듈로(%) 연산과 인덱스 계산을 조합하면 한 줄의 컴프리헨션만으로 회전을 구현할 수 있습니다. 왼쪽 회전은 (i + 3) % len(test_list), 오른쪽 회전은 (i - 3) % len(test_list)를 인덱스로 사용합니다.
# 리스트 컴프리헨션(list comprehension) 방식
# 리스트 초기화
test_list = [1, 4, 6, 7, 2]
# 원본 리스트 출력
print("Original list : " + str(test_list))
# 컴프리헨션으로 왼쪽 3칸 회전
test_list = [test_list[(i + 3) % len(test_list)]
for i, x in enumerate(test_list)]
# 왼쪽 회전 결과 출력
print("List after left rotate by 3 : " + str(test_list))
# 컴프리헨션으로 오른쪽 3칸 회전 (원상 복구)
test_list = [test_list[(i - 3) % len(test_list)]
for i, x in enumerate(test_list)]
# 오른쪽 회전 결과 출력
print("List after right rotate by 3(back to original) : " + str(test_list))동작 원리: 각 위치 i에 대해 새 리스트의 값은 (i ± 3)을 리스트 길이로 나눈 나머지 인덱스의 원소가 됩니다. 나머지 연산 덕분에 인덱스가 범위를 벗어나지 않으며, 회전 칸 수가 리스트 길이보다 커도 올바르게 동작한다는 장점이 있습니다.
3. collections.deque의 rotate() 메서드 활용
collections 모듈의 deque는 회전 전용 메서드인 rotate()를 기본으로 제공합니다. 양수를 전달하면 오른쪽, 음수를 전달하면 왼쪽으로 회전하며, 성능 면에서도 매우 효율적입니다. 리스트로 변환해 사용하면 됩니다.
# deque의 rotate() 메서드 방식
from collections import deque
# 리스트 초기화
test_list = [1, 4, 6, 7, 2]
# 원본 리스트 출력
print("Original list : " + str(test_list))
# rotate()로 왼쪽 3칸 회전 (음수 = 왼쪽)
test_list = deque(test_list)
test_list.rotate(-3)
test_list = list(test_list)
# 왼쪽 회전 결과 출력
print("List after left rotate by 3 : " + str(test_list))
# rotate()로 오른쪽 3칸 회전 (양수 = 오른쪽, 원상 복구)
test_list = deque(test_list)
test_list.rotate(3)
test_list = list(test_list)
# 오른쪽 회전 결과 출력
print("List after right rotate by 3(back to original) : " + str(test_list))실행 결과
세 가지 방법 모두 동일한 결과를 출력합니다.
Original list : [1, 4, 6, 7, 2] List after left rotate by 3 : [7, 2, 1, 4, 6] List after right rotate by 3(back to original) : [1, 4, 6, 7, 2] Original list : [1, 4, 6, 7, 2] List after left rotate by 3 : [7, 2, 1, 4, 6] List after right rotate by 3(back to original) : [1, 4, 6, 7, 2] Original list : [1, 4, 6, 7, 2] List after left rotate by 3 : [7, 2, 1, 4, 6] List after right rotate by 3(back to original) : [1, 4, 6, 7, 2]
마무리 및 방법 선택 가이드
- 슬라이싱: 문법이 단순하고 추가 임포트가 필요 없어 가장 많이 사용되는 표준적인 방법입니다.
- 리스트 컴프리헨션: 인덱스 기반 로직이 필요하거나 회전과 함께 다른 변환을 적용할 때 유용합니다.
- deque.rotate(): 대용량 데이터나 빈번한 회전 연산에서 성능이 뛰어나며, 코드 가독성도 우수합니다.
세 방법 모두 시간 복잡도는 O(n)으로 동일하지만, 상황과 코드 스타일에 따라 적합한 방식을 선택하면 더 깔끔하고 효율적인 파이썬 코드를 작성할 수 있습니다.