Python Basic 8 (Collections : Counter, Defaultdict, OrdererdDict, Deque, NamedTuple)
Collections 가 Python의 꽃이라고 할 수 있을까 싶다.
C, Java, Python 을 거치면서 결국 Python을 주 언어로 선택한 것은 Python의 Collections 같은 모듈 때문이다. 물론 Java나 C 보다 속도나 유지보수성은 떨어지지만, 편리한 모듈들이 많아서 코딩하기 편하고, 범용성이 높기 때문이다.
Collections가 특히나 그렇다. Collections에 대한 자세한 설명은 아래 공식 문서를 참조하면 좋을 듯하다.
collections — Container datatypes — Python 3.10.0 documentation
collections — Container datatypes Source code: Lib/collections/__init__.py This module implements specialized container datatypes providing alternatives to Python’s general purpose built-in containers, dict, list, set, and tuple. namedtuple() factory f
docs.python.org
그리고 모든 모듈은 import collections 해서 사용하도록 한다.
1. Counter
container = collections.Counter()
print(container)
container.update("aabbcsscccff")
print(container)
container.update("cccccccccccccc")
print(container)
for n in "abccdfe":
print('%s:%d' %(n, container[n]), end=" ")
print()
# Counter()
# Counter({'c': 4, 'a': 2, 'b': 2, 's': 2, 'f': 2})
# Counter({'c': 18, 'a': 2, 'b': 2, 's': 2, 'f': 2})
# a:2 b:2 c:18 c:18 d:0 f:2 e:0
당연히 Dictionary 형태이므로 Dictionary에서 사용했던 .update(), .values(), .items(), .keys(), get() 등등 다 쓸 수 있다.
2. DefaultDict
DefaultDict는 단순하게 dictionary를 만들 때, 없는 key를 호출하거나, 값이 없는 채로 key를 만들었다면 default 값을 주어서 그 값이 나오게 하는 객체이다. 보통 defaultdict(매개변수) → 매개변수는 반드시 callable한 객체여야 한다. int, list, 그리고 default값을 호출하는 function이 들어가면 된다. 예를 들어 int가 들어가면 default값은 0이다. str일 경우에는 "" 공백 문자열이 자동으로 생성된다.
import collections
def default_value_func():
return "default_value"
dic = collections.defaultdict(default_value_func)
dic2 = collections.defaultdict(int)
dic['n1'] = 35
print(dic["n1"])
print(dic['n2'])
print(dic)
dic2['n1'] = 20
print(dic2)
print(dic2['n2'])
# 35
# default_value
# defaultdict(<function default_value_func at 0x000001AE2FD171F0>, {'n1': 35, 'n2': 'default_value'})
# defaultdict(<class 'int'>, {'n1': 20})
# 0
3. Deque
개인적으로 자료구조나 알고리즘에서 deque와 heapq를 가장 많이 사용한다고 생각한다.
헷갈릴까봐 먼저 정리하자면, deque는 양쪽에서 다 넣을 수 있는 queue라고 생각하면 된다. (컨테이너 앞뒤에 넣거나 뺄 수 있다.)
문자열(str), list, 혹은 dictionary를 deque로 만들 수 있다. (하지만 굳이 dictonary를 deque로 사용할 이유가 없다..)
deque를 사용하는 이유 중 하나는 list에 비해 효율적인 저장 방식을 지원한다는 것이다. list의 경우 pop()으로 마지막 값을 꺼내는 경우 O(1)의 시간이 걸리는데 pop(0)을 할 경우 list 크기에 따라 읽어오는 시간이 달라지는 O(n)의 시간이 소요된다. 하지만 deque의 경우에는 pop()과 popleft()의 경우 모두 동일하게 O(1)와 동일한 시간이 걸린다. index의 주소값으로 바로 값을 찾는다는 의미이다.
따라서, 효율성을 생각한다면 deque를 쓰는게 좋다.
# 만드는 것은 list, str, dict 모두 가능
deq1 = collections.deque('Nice to meet you')
deq2 = collections.deque({
1: 'Hi',
2: 'My name is Katie',
3: 23
})
deq3 = collections.deque(["aaa", 'BBB', 'ccc'])
이렇게 deque로 모두 만들 순 있지만 deq2 처럼 dictionary로 만드는 것은 아무 의미가 없다. 어차피 dictionary 자체가 key 값으로 value를 찾아올 수 있기도 하고, pop()을 해서 value 값을 불러올 수 있는 것도 아니기 때문이다.
deque에서 사용할 수 있는 기능들은 queue + stack + list 의 세가지를 합친 기능이라고 생각하면 쉽다.
stack에서 사용하는 것처럼 Last In First Out (LIFO) 넣은 쪽으로 빼는(편의상 오른쪽) .append() 와 .pop()이 있다.
queue에서 사용하는 것처럼 First In First Out으로 넣은 쪽 반대쪽으로 빼는 .append()이면 .popleft(), .appendleft()했으면 .popleft()를 할 수 있다.
list처럼 사용도 가능하다. 특정 원소를 insert하기 위해서 deq[index] = value 나 deq.insert(index, value) 형태로 삽입도 할 수 있고, .remove('value')해서 삭제도 가능하다. list에서 가능한 .reverse()나 sorted(iterable)도 사용 가능하다. .sort()는 불가하다. 원본 변화시키고 싶으면 iterable = sorted(iterable) 형태로 직접 원본 변화시켜줘야 한다.
그리고 str로 돌아가려면 일일히 원소 꺼내서 str += 원소 해서 만들어주면 된다.
deq1 = collections.deque('Nice to meet you')
deq1 = sorted(deq1)
sample = ""
for i in deq1 :
sample += i
print(sample)
# Nceeeimoottuy
str에서는 못하던 reverse, append 등을 deque로 바꾸면 가능해진다는 것이다. 이걸 잘 활용하자. 이게 가능한 이유는 deque로 만들면 str의 요소를 다 찢어서 list형태로 저장해주기 때문이다.
str에서 쓸 수 있는 기능들은 내장함수에 국한되어 있다. ( 각 데이터타입 별로 쓸 수 있는 함수들을 볼 수 있는 명령어는 변수.__dir__() , 혹은 dir(변수명) 이다 : 생각 안나면 이런식으로라도 찾아서 쓰자)
간단하게 str에서 많이 쓰이는 내장함수들을 적어보자면,
chr(유니코드값) : 해당 유니코드의 문자 출력
divmod(a,b) a/b의 몫과 나머지
enumerate(iterable) : index와 값의 형태로 묶여 있는 enumerate 객체가 됨 (enumerate은 반드시 for 문 돌려야 내용 볼 수 있음)
teststr = "aaabbbccc112233"
for i, j in enumerate(teststr):
print(i, j)
eval(expression)은 실행 가능한 문자열을 입력으로 받아들여 문자열 실행 결과값을 돌려준다.그 외에도 filter(함수/lambda, 걸러낼 대상), abs, any, all, 등 여러가지가 있다.
내장 함수 — Python 3.10.0 문서
내장 함수 파이썬 인터프리터에는 항상 사용할 수 있는 많은 함수와 형이 내장되어 있습니다. 여기에서 알파벳 순으로 나열합니다. abs(x) 숫자의 절댓값을 돌려줍니다. 인자는 정수, 실수 또는 __
docs.python.org
말이 다른 방향으로 튄것 같다..
다시 deque로 돌아와서,
원소 꺼내고 넣고 하는 건 이런 형태로 보통 사용한다.
deq = collections.deque("Hello Python")
while True:
try:
print(deq.popleft(), end = ''),
except IndexError:
break
# Hello Python
4. NamedTuple
이름을 정해주는 애라고 생각하면 된다. 사용도가 높진 않은 것 같다.
Person = collections.namedtuple("P", "name age gender")
aa = Person(age=24, name="윤지창", gender="남")
bb = Person(name="윤은경", age=26, gender="여")
for n in [aa, bb]:
print("%s는(은) %d세인 %s이다" %n)
# 윤지창는(은) 24세인 남이다
# 윤은경는(은) 26세인 여이다
5. OrderedDict
자료의 순서를 기억하는 사전형 클래스라고 생각하면 된다.
dictionary에 뭐가 먼저 들어왔는지 기억하고 있어, 순서까지 고려한 True, False가 가능하다. 사용 빈도는 높지 않은 것 같다.