목차
딕셔너리
키/값 구조로 이뤄진 딕셔너리.
파이썬 3.7+에서는 입력 순서가 유지됨
내부적으로는 해시 테이블 Hash Table 로 구현.(11장)
각 언어별 해시 테이블 구현
인덱스를 숫자로만 지정할 수 있는 리스트와 달리 딕셔너리는 문자를 포함해 다양한 타입을 키로 사용 가능
해시 테이블은 다양한 타입을 키로 지원,
- 입력과 조회 모두 O(1)에 가능.
- 물론 해시 테이블은 최악의 경우 O(n)이 될 수 있으나 대부분의 경우 훨씬 더 빨리 실행
- 분할 상환 분석 Amortized Analysis 에 따른 시간 복잡도는 O(1).
- 해시 테이블의 주요 연산과 시간 복잡도
연산 | 시간 복잡도 | 설명 |
---|---|---|
len(a) | O(1) | 요소의 개수를 리턴 |
a[key] | O(1) | 키를 조회하여 값을 리턴 |
a[key] = value | O(1) | 키/값을 삽입 |
key in a | O(1) | 딕셔너리에 키가 존재하는지 확인 |
이처럼 딕셔너리는 대부분의 연산이 O(1)에 처리 가능한 매우 우수한 자료형임.
입력순서유지
원래 파이썬에서 딕셔너리는 입력 순서가 유지되지 않았음
- 마찬 가지로 대부분의 언어에서 해시 테이블을 이용한 자료형은 입력 순서가 유지되지 않음.
- 파이썬도 3.6 이하에서는 입력 순서가 유지되지 않아 collections.OrderedDict() 라는 별도 자료형을 제공했음.
- 그러나 파이썬 3.7부터는 내부적으로 인덱스를 이용해 입력 순서를 유지하도록 개선됨.
-
다만, 여전히 3.6 이하 버전을 사용하는 곳이 많아 인터프리터의 버전을 정확히 확인할 수 없는 상황에 서는 입력 순서가 유지되지 않을 수 있음 -> 딕셔너리의 입력 순서가 유지될 것이라고 가정하고 진행하는 것은 매우 위험하며 권장하지 않음.
- 파이썬 3.7+: 딕셔너리 입력 순서 유지
- 파이썬 3.6+: 딕셔너리 메모리 사용량 20% 감소
collections
파이썬 3.6 이하에서 collections.OrderedDict()
: 항상 입력 순서가 유지 collections.defaultdict()
: 조회 시 항상 디폴트 값을 생성해 키 오류를 방지 collections.Counter()
: 요소의 값을 키로 하고 개수를 값 형태로 만들어 카운팅
딕셔너리의 활용 방법
딕셔너리 선언
>>> a = dict()
중괄호를 써서 좀 더 간단하게 선언할 수 있다.
>>> a = {}
다음과 같이 key1 , key2 는 초기값으로 지정해 선언하거나 key3 처럼 나중에 별도로 선언 하여 value3 라는 값을 할당 가능.
>>> a = {'key1':'value1', 'key2':'value2'}
>>> a
{'key1': 'value1', 'key2': 'value2'}
>>> a['key3'] = 'value3'
>>> a
{'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
딕셔너리 값 조회, 예외처리
키를 지정하면 가능
존재하지 않는 키를 조회할 경우에는 에러가 발생
- try 구문으로 예외 처리
>>> a['key1']
'value1'
>>> a['key4']
Traceback (most recent call last):
File "<stdin>", line 1, in <module> KeyError: 'key4'
예외처리
try:
print(a['key4'])
except KeyError:
print('존재하지 않는 키')
[PROBLEM]
KeyError 는 다음과 같이 키를 삭제할 때도 발생한다.
>>> del a['key4']
Traceback (most recent call last):
File "<stdin>", line 1, in <module> KeyError: 'key4'
[SOLVE]
try 구문으로 예외 처리
or
다음과 같이 미리 확인
>>> 'key4' in a
False
>>> if 'key4' in a:
... print('존재하는 키')
... else:
... print('존재하지 않는 키')
...
존재하지 않는 키
키&값 동시조회
키/값은 for 반복문으로 조회 가능
딕셔너리의 items() 메소드를 사용하면 키와 값을 각각 꺼내올 수 있음.
>>> for k,v in a.items():
... print(k,v)
...
key1 value1
key2 value2
key3 value3
----
딕셔너리 키 삭제
**del**
로 삭제
>>> del a['key1']
>>> a
{'key2': 'value2', 'key3': 'value3'}
딕셔너리 모듈
defaultdict 객체
존재하지 않는 키를 조회할 경우, 에러 메시지를 출력하는 대신 디폴트 값을 기준으로 해당 키에 대한 딕셔너리 아이템을 생성.
실제로는 collections.defaultdict 클래스를 갖음
없는 것 에러발생시키지 않고 디폴트값으로 만들어서 출력
>>> a = collections.defaultdict(int)
>>> a['A'] = 5
>>> a['B'] = 4
>>> a
defaultdict(<class 'int'>, {'A': 5, 'B': 4})
>>> a['C'] += 1
>>> a
defaultdict(<class 'int'>, {'A': 5, 'B': 4, 'C': 1})
이제 C 는 존재하지 않는 키임.
원래의 딕셔너리라면 앞서 ‘딕셔너리의 활용 방법’ 절에서 살펴본 것처럼 KeyError 가 발생하겠지만,
defaultdict 객체는 에러 없이 바로 +1 연산이 가능하고 이 경우 디폴트인 0을 기준으로 자동으로 생성한 후 여기에 1을 더해 최종적으로 1이 만들어짐.
여기서도 결과를 보면 {‘A’: 5, ‘B’: 4, ‘C’: 1} , 이렇게 3개의 아이템이 존재하는 것을 확인 가능
Counter 객체
아이템에 대한 개수를 계산해 딕셔너리로 리턴
- 키에는 아이템의 값이,
- 값에는 해당 아이템의 개수가 들어간 딕셔너리를 생성.
실제로는 다음과 같이 딕셔너리를 한 번 더 래핑 Wrapping 한collections.Counter 클래스를 갖음
[사용법]
>>> a = [1, 2, 3, 4, 5, 5, 5, 6, 6]
>>> b = collections.Counter(a)
>>> b
Counter({5: 3, 6: 2, 1: 1, 2: 1, 3: 1, 4: 1})
# 딕셔너리를 한 번 더 래핑 Wrapping 한collections.Counter 클래스
>>> type(b)
<class 'collections.Counter'>
most_common()
Counter 객체에서 가장 빈도 수가 높은 요소 추출 딕셔너리 이름.most_common(추출 개수)
>>> b.most_common(2)
[(5, 3), (6, 2)]
OrderedDict 객체
대부분의 언어에서 해시 테이블을 이용한 자료형은 입력 순서가 유지되지 않음
-
- 파이썬 3.6 이하
- 입력 순서가 유지되는 OrderedDict 라는 별도의 객체를 제공.
- 입력값을 부여할 경우 OrderedDict 는 입력 그대로 순서가 유지됨.
-
- OrderedDict은 순서와 관련된 몇 가지 추가 메소드를 제공한다는 점 이외에는 사실상 하위 호환성을 위해서만 남겨짐
- 그러나 코딩 테스트 시 하위 버전의 파이썬 인터프리터를 사용하는 경우가 있고, 원래 해시 테이블은 입력 순서에 관여하지 않는 자료형인 만큼, 무턱대고 딕셔너리로 입력 순서를 기대하는 것은 매우 위험하며 권장하지도 않는 방법이다.
- 이제는 대부분의 코딩 테스트 사이트가 3.7 이상을 사용하므로 이런 경우는 드물겠지만, 여전히 딕셔너리에서 입력 순서를 기대하는 것에는 유의 필요.
>>> collections.OrderedDict({'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2})
OrderedDict([('banana', 3), ('apple', 4), ('pear', 1), ('orange', 2)])
타입 선언
기호를 사용하여 간편하게 타입 선언
기존의 이름으로 타입선언
>>> a = list()
>>> type(a)
<class 'list'>
기호로 선언
>>> type([])
<class 'list'>
>>> type(())
<class 'tuple'>
>>> type({})
<class 'dict'>
>>> type({1})
<class 'set'>
-
- 딕셔너리와 집합
- 같은 중괄호 {}를 사용하지만 키의 존재 유무로 서로 다른 자료형으로 선언