티스토리 뷰

반응형

리스트에서 중복된 원소를 제거하려고 하는 상황을 가정해보자. 보통은 이런식의 코드를 생각하기 쉽다.

def uniq(aList):
  result = []
  for a in aList:
    if result.count(a) < 1:
      result.append(a)
  return result

임시 리스트를 만들고, 원본 리스트의 각 원소를 순회하면서 임시 리스트에 "들어있지 않다면" 추가하는 작업을 반복하여 임시리스트가 중복을 제거한 리스트를 담도록 하는 것이다. 여기서는 '.count()를 통해서 멤버십 테스트를 하는 부분을in` 연산자로 바꾸면 좀 더 좋은 성능을 (그리고 좀 더 깔끔한 코드를) 얻을 수 있다.

또 다른 방법으로는 리스트 축약을 사용하는 방법이 있다. 별도의 임시 리스트를 만들지 않고 i 번째 원소가 0 ~ i-1 번째 원본의 부분열에서 나타나는지를 검사해서 중복을 체크하는 것이다.

def uniq(aList):
  return [x for i, x in enumerate(aList) if x not in aList[:i]]

위 코드는 각 원소에 대해서 해당 원소가 원본 리스트의 자신의 위치보다 앞에 출현한적이 있으면 제외하는 식으로 필터링하여 한번에 리스트를 만들어 낸다. 다만 리스트가 매우 길고, 중복 원소의 빈도가 높으면 높을수록 성능상으로는 불리하다.

set을 사용하기

set()을 사용하면 중복 원소를 매우 손쉽게 제거해낼 수 있다. 리스트의 in 연산, 즉 멤버십 테스트가 전체 원소에 대해 순회하면서 검사하는 것임에 반해, set은 주어진 값의 해시 값을 이용해서 해당 해시에 대응하는 원소가 있는지를 비교하기 때문에 매우 빠르게 중복을 제거한다.

다만, set의 경우 순서가 없는 집합이기 때문에, 원본 리스트에서의 순서를 유지하지 못한다. 이 제약이 필요없거나, 중복을 제거한 결과를 다시 정렬하는 등의 처리를 할 거라면 set은 가장 높은 우선순위로 고려할 방법이다. 리스트를 set으로 변환하기 위해서는 단순히 해당 리스트를 set() 함수의 인자로 전달하기만 하면 된다.

without_dups = set(aList)

OrderedDict

OrderedDict 는 값의 삽입 순서를 기억하는 사전이다. 따라서 set이나 dict와 같이 매우 빠른 멤버십 테스트를 지원하면서 추가 순서를 유지할 수 있다. 이를 사용하여 아무 값이나 갖는 사전을 만들고, 그 키를 리스트로 변환하면 된다.

from collections import OrderedDict

def uniq3(aList):
  d = OrderedDict()
  for i in aList:
    d[i] = True
  return list(d.keys()) 



파이썬 3.6부터 사전의 키는 사전에 추가된 순서를 유지하게 되었다. 따라서 따로 OrderedDict를 사용하지 않더라도 위 기능을 순수하게 사전으로만 구현해도 잘 동작하게 된다.

반응형

'파이썬 how to' 카테고리의 다른 글

재귀  (0) 2023.04.29
그리드 형식의 값을 다루는 방법  (0) 2017.11.13
표준입력과 input 함수로 파일 읽어들이기  (0) 2017.10.31
파일입출력 : 파일을 읽고 쓰는 방법  (0) 2017.10.28
CSV 파일 다루기  (0) 2017.10.10
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함