알고리즘 문제를 효율적으로 풀기위해 많이 사용되는 python의 내장 라이브러리 collections에 대해 python 공식 설명서를 같이 뜯어보자.
이 모듈은 파이썬의 범용 내장 컨테이너 dict, list, set 및 tuple에 대한 대안을 제공하는 특수 컨테이너 데이터형을 구현합니다.
모듈 | 설명 |
---|---|
namedtuple() | 이름 붙은 필드를 갖는 튜플 서브 클래스를 만들기 위한 팩토리 함수 |
deque | 양쪽 끝에서 빠르게 추가와 삭제를 할 수 있는 리스트류 컨테이너 |
ChainMap | 여러 매핑의 단일 뷰를 만드는 딕셔너리류 클래스 |
Counter | hashable 객체들을 계산하는 데 사용되는 딕셔너리 서브 클래스 |
OrderedDict | 항목이 추가된 순서를 기억하는 딕셔너리 서브 클래스 |
defaultdict | 누락된 값을 제공하기 위해 팩토리 함수를 호출하는 딕셔너리 서브 클래스 |
UserDict | 딕셔너리 객체를 감싸는 래퍼로서 더 쉬운 딕셔너리 서브 클래싱을 제공 |
UserList | 리스트 객체를 감싸는 래퍼로서 더 쉬운 리스트 서브 클래싱을 제공 |
UserString | 문자열 객체를 감싸는 래퍼로서 더 쉬운 문자열 서브 클래싱을 제공 |
ChainMap은 여러 개의 매핑(mapping)을 하나의 뷰(view)로 만들어주는 딕셔너리류 클래스입니다. 이를 통해 여러 개의 딕셔너리나 매핑 객체를 연결하여 하나의 매핑처럼 다룰 수 있습니다.
ChainMap은 여러 매핑을 연결한 순서대로 탐색을 진행합니다. 처음에 전달된 매핑에서 키를 찾지 못하면 다음 매핑을 검색하며, 마지막으로 기본 딕셔너리(빈 딕셔너리)까지 탐색합니다. 따라서, 여러 개의 매핑을 하나의 매핑으로 묶어 편리하게 사용할 수 있습니다.
ChainMap의 중요한 메서드와 속성은 다음과 같습니다:
new_child(m=None, **kwargs): 현재 ChainMap에 새로운 매핑을 추가하여 새로운 ChainMap을 반환합니다. m이 지정되면 새로운 매핑이 추가되고, 지정되지 않으면 빈 딕셔너리가 사용됩니다. kwargs를 통해 키워드 인자로 전달된 매핑이나 새로운 빈 딕셔너리를 업데이트할 수 있습니다.
maps: ChainMap에 포함된 모든 매핑 객체의 리스트를 반환합니다. 이 리스트는 ChainMap의 검색 순서를 반영합니다.
parents: ChainMap에서 첫 번째 매핑을 제외한 나머지 매핑들의 ChainMap을 반환합니다.
maps[0]: ChainMap에서 첫 번째 매핑을 반환합니다.
다음은 ChainMap의 예시 코드입니다:
from collections import ChainMap
# 매핑 객체들 생성
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
dict3 = {'c': 5, 'd': 6}
# ChainMap 생성
chain_map = ChainMap(dict1, dict2, dict3)
# 매핑 조회
print(chain_map['a']) # 출력: 1
print(chain_map['b']) # 출력: 2 (dict1에서 탐색)
print(chain_map['c']) # 출력: 4 (dict2에서 탐색)
print(chain_map['d']) # 출력: 6 (dict3에서 탐색)
# ChainMap 생성 (dict2를 첫 번째로 위치시킴)
chain_map = ChainMap(dict2, dict1, dict3)
# 매핑 조회
print(chain_map['b']) # 출력: 3 (dict2에서 탐색)
Counter를 사용하면 리스트, 문자열, 튜플 등과 같은 반복 가능한(iterable) 객체의 요소들의 개수를 쉽게 세고 관리할 수 있습니다.
from collections import Counter
# 문자열의 요소 개수 세기
string = "abracadabra"
counter = Counter(string)
print(counter) # 출력: Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
# 요소 개수 업데이트
counter.update("aaa")
print(counter) # 출력: Counter({'a': 8, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
# 요소 조회
print(counter['a']) # 출력: 8
# 요소 삭제
del counter['b']
print(counter) # 출력: Counter({'a': 8, 'r': 2, 'c': 1, 'd': 1})
# Counter 객체 간 연산
counter2 = Counter("aaaabbbb")
sum_counter = counter + counter2
print(sum_counter) # 출력: Counter({'a': 12, 'b': 6, 'r': 2, 'c': 1, 'd': 1})
Counter 메서드와 속성에 대해 예시를 들어 설명해드리겠습니다:
elements(): elements() 메서드는 Counter 객체에 포함된 요소들을 반복 가능한 객체로 반환합니다. 반환된 객체는 요소들을 중복 없이 포함하며, 요소의 반복은 해당 요소의 개수만큼 이루어집니다.
c = Counter(a=4, b=2, c=0, d=-2)
sorted(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']
most_common(n): most_common() 메서드는 가장 일반적인(빈도가 높은) 요소를 먼저 포함하는 리스트를 반환합니다. n을 지정하면 가장 일반적인 n개의 요소만 반환됩니다. 반환된 리스트의 각 요소는 (요소, 개수)의 튜플 형태
from collections import Counter
counter = Counter(a=3, b=2, c=1)
most_common = counter.most_common(2)
print(most_common)
출력
[('a', 3), ('b', 2)]
subtract(iterable_or_mapping) : subtract() 메서드는 다른 반복 가능한 객체나 매핑 객체의 요소들을 현재 Counter 객체에서 뺍니다. subtract() 메서드를 호출하는 Counter 객체의 요소가 해당 요소들을 빼는 연산을 수행합니다.
from collections import Counter
counter = Counter(a=3, b=2, c=1)
other_counter = Counter(a=1, b=2, d=4)
counter.subtract(other_counter)
print(counter)
출력
from collections import Counter
counter = Counter(a=3, b=2, c=1)
other_counter = Counter(a=1, b=2, d=4)
counter.subtract(other_counter)
print(counter)
total(): total() 메서드는 Counter 객체에 포함된 모든 요소들의 개수를 반환합니다.
from collections import Counter
counter = Counter(a=3, b=2, c=1)
total = counter.total()
print(total)
출력
6
collections 모듈의 deque 클래스는 양쪽 끝에서 빠르게 추가와 삭제를 할 수 있는 리스트류 컨테이너입니다. deque는 "double-ended queue"의 줄임말로, 큐(Queue)와 스택(Stack)의 기능을 모두 제공하는 자료구조입니다.
deque 클래스의 일부 주요한 메서드와 속성은 다음과 같습니다:
from collections import deque
d = deque('ghi') # make a new deque with three items
for elem in d: # iterate over the deque's elements
print(elem.upper())
G
H
I
d.append('j') # add a new entry to the right side
d.appendleft('f') # add a new entry to the left side
d # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])
d.pop() # return and remove the rightmost item
'j'
d.popleft() # return and remove the leftmost item
'f'
list(d) # list the contents of the deque
['g', 'h', 'i']
d[0] # peek at leftmost item
'g'
d[-1] # peek at rightmost item
'i'
list(reversed(d)) # list the contents of a deque in reverse
['i', 'h', 'g']
'h' in d # search the deque
True
d.extend('jkl') # add multiple elements at once
d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
d.rotate(1) # right rotation
d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
d.rotate(-1) # left rotation
d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
deque(reversed(d)) # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
d.clear() # empty the deque
d.pop() # cannot pop from an empty deque
Traceback (most recent call last):
File "<pyshell#6>", line 1, in -toplevel-
d.pop()
IndexError: pop from an empty deque
d.extendleft('abc') # extendleft() reverses the input order
d
deque(['c', 'b', 'a'])