파이썬으로 코딩하다 보면 리스트 안에서 두 번 이상 반복해서 등장하는 요소를 제거하고, 오직 한 번만 나타난 항목만 원래의 순서대로 남겨야 하는 상황이 종종 발생합니다. 이 글에서는 그 문제를 해결하는 알고리즘과 실제 코드를 단계별로 살펴보겠습니다.
문제 정의
숫자로 이루어진 리스트 nums가 주어졌다고 가정해 봅시다. 이때 여러 번 등장하는 숫자들은 모두 제거하고, 원본 리스트에서 처음 나타난 순서는 그대로 유지해야 합니다.
예를 들어 입력이 nums = [2, 4, 6, 1, 4, 6, 9]라면 출력은 [2, 1, 9]가 됩니다. 4와 6은 리스트에 두 번씩 등장하기 때문에 제외되고, 딱 한 번만 나타난 2, 1, 9만 남게 되기 때문입니다.
해결 접근 방식
핵심 아이디어는 각 요소의 등장 횟수를 먼저 센 뒤, 한 번만 등장한 요소만 골라내는 것입니다. 구체적인 단계는 다음과 같습니다.
- 등장 횟수를 저장할 빈 딕셔너리(
dict)를 생성합니다. nums의 각 요소i에 대해 아래 작업을 수행합니다.i가 딕셔너리에 없으면dict[i] = 0으로 초기화합니다.dict[i]값을 1씩 증가시켜 등장 횟수를 누적합니다.
- 마지막으로 딕셔너리에서 값이 1인(즉, 한 번만 등장한) 키들만 모아 리스트로 반환합니다.
구현 예제 코드
class Solution:
def solve(self, nums):
dict = {}
for i in nums:
if i not in dict:
dict[i] = 0
dict[i] = dict[i] + 1
return [k for k, v in dict.items() if v == 1]
ob = Solution()
nums = [2, 4, 6, 1, 4, 6, 9]
print(ob.solve(nums))입력
[2, 4, 6, 1, 4, 6, 9]
출력
[2, 1, 9]
더 간결한 대안: collections.Counter 활용
파이썬 표준 라이브러리의 collections.Counter를 사용하면 위 로직을 훨씬 짧은 코드로 구현할 수 있습니다. 또한 딕셔너리의 삽입 순서가 유지되는 파이썬 3.7 이상 환경이라면 원본 순서도 자연스럽게 보존됩니다.
from collections import Counter
def solve(nums):
count = Counter(nums)
return [x for x in nums if count[x] == 1]
nums = [2, 4, 6, 1, 4, 6, 9]
print(solve(nums)) # [2, 1, 9]시간 복잡도 분석
두 방식 모두 리스트를 한 번 순회하며 등장 횟수를 세고(O(n)), 다시 한 번 순회하며 조건에 맞는 요소를 필터링하기 때문에 전체 시간 복잡도는 O(n)입니다. 추가로 저장 공간도 O(n)만큼 필요하므로, 리스트 크기가 커져도 효율적으로 동작합니다.
정리
리스트에서 중복된 항목을 걸러내고 고유한 요소만 순서대로 남기려면, 딕셔너리나 Counter로 각 값의 등장 횟수를 집계한 후 값이 1인 항목만 추출하면 됩니다. 이 패턴은 데이터 정제, 로그 분석, 중복 제거 전처리 작업 등 다양한 실무 상황에서 유용하게 활용할 수 있습니다.