Python 딕셔너리

딕셔너리란?

  • 키-값 쌍으로 데이터를 저장하는 자료형
  • 키는 불변(immutable) 타입만 가능: 문자열, 숫자, 튜플
  • 값은 모든 타입 가능
  • Python 3.7+부터 삽입 순서 유지

딕셔너리 생성

d = {"a": 1, "b": 2}
d = dict(a=1, b=2)              # 키가 문자열일 때
d = dict([("a", 1), ("b", 2)])  # 튜플 리스트에서
d = dict(zip(["a", "b"], [1, 2]))  # zip으로 생성
d = {}                          # 빈 딕셔너리
d = dict()

# 컴프리헨션
d = {x: x**2 for x in range(5)}  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

접근 (Read)

d = {"name": "Alice", "age": 25}

# 기본 접근
d["name"]           # "Alice"
d["city"]           # KeyError!

# get() - 안전한 접근
d.get("name")       # "Alice"
d.get("city")       # None (에러 없음)
d.get("city", "Seoul")  # "Seoul" (기본값 지정)

# 키 존재 여부
"name" in d         # True
"city" not in d     # True

# 키, 값, 쌍 가져오기
d.keys()            # dict_keys(['name', 'age'])
d.values()          # dict_values(['Alice', 25])
d.items()           # dict_items([('name', 'Alice'), ('age', 25)])

# 리스트로 변환
list(d.keys())      # ['name', 'age']

추가/수정 (Create/Update)

d = {"a": 1}

# 기본 추가/수정
d["b"] = 2          # 추가: {"a": 1, "b": 2}
d["a"] = 10         # 수정: {"a": 10, "b": 2}

# update() - 여러 개 추가/수정
d.update({"c": 3, "d": 4})
d.update(e=5, f=6)  # 키가 문자열일 때
d.update([("g", 7)])

# setdefault() - 없을 때만 추가
d.setdefault("new", 100)  # "new" 없으면 추가, 있으면 유지
# 값 반환: 기존 값 또는 새로 설정된 값

삭제 (Delete)

d = {"a": 1, "b": 2, "c": 3}

# pop() - 키로 삭제 후 값 반환
d.pop("a")          # 1 반환, {"b": 2, "c": 3}
d.pop("x", None)    # 없으면 None 반환 (에러 방지)

# popitem() - 마지막 쌍 삭제 후 반환
d.popitem()         # ("c", 3) 반환

# del
del d["b"]          # {"c": 3}

# clear()
d.clear()           # {}

순회 (Iteration)

d = {"a": 1, "b": 2, "c": 3}

# 키 순회 (기본)
for key in d:
    print(key)

# 값 순회
for value in d.values():
    print(value)

# 키-값 쌍 순회
for key, value in d.items():
    print(key, value)

# enumerate와 함께
for i, (key, value) in enumerate(d.items()):
    print(i, key, value)

딕셔너리 컴프리헨션

# 기본
{x: x**2 for x in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# 조건 필터링
{x: x**2 for x in range(10) if x % 2 == 0}
# {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}

# 키-값 변환
d = {"a": 1, "b": 2}
{v: k for k, v in d.items()}  # {1: "a", 2: "b"} (키↔값 교환)

# 리스트에서 딕셔너리 생성
names = ["Alice", "Bob", "Charlie"]
{name: len(name) for name in names}
# {'Alice': 5, 'Bob': 3, 'Charlie': 7}

# 두 리스트 합치기
keys = ["a", "b", "c"]
values = [1, 2, 3]
{k: v for k, v in zip(keys, values)}
# dict(zip(keys, values))  # 더 간단

병합 (Merge)

a = {"x": 1, "y": 2}
b = {"y": 3, "z": 4}

# | 연산자 (Python 3.9+)
a | b               # {'x': 1, 'y': 3, 'z': 4}
b | a               # {'y': 2, 'z': 4, 'x': 1}

# |= 연산자 (원본 수정)
a |= b

# ** 언패킹 (Python 3.5+)
{**a, **b}          # {'x': 1, 'y': 3, 'z': 4}

# update() (원본 수정)
a.update(b)

defaultdict

from collections import defaultdict

# 기본값이 있는 딕셔너리
d = defaultdict(int)      # 기본값 0
d["a"] += 1               # {"a": 1} (KeyError 없음)

d = defaultdict(list)     # 기본값 []
d["a"].append(1)          # {"a": [1]}

d = defaultdict(set)      # 기본값 set()
d["a"].add(1)

# 그룹핑에 활용
data = [("fruit", "apple"), ("fruit", "banana"), ("veg", "carrot")]
d = defaultdict(list)
for category, item in data:
    d[category].append(item)
# {'fruit': ['apple', 'banana'], 'veg': ['carrot']}

# 단어 빈도 세기
text = "hello world hello"
d = defaultdict(int)
for word in text.split():
    d[word] += 1
# {'hello': 2, 'world': 1}

Counter

from collections import Counter

# 빈도 세기
c = Counter("hello")         # {'l': 2, 'h': 1, 'e': 1, 'o': 1}
c = Counter([1, 1, 2, 3, 3, 3])  # {3: 3, 1: 2, 2: 1}

# 메서드
c.most_common(2)             # [('l', 2), ('h', 1)] 상위 2개
c.elements()                 # 요소 반복자
c.update([1, 1])             # 빈도 추가
c.subtract([1])              # 빈도 감소

# 연산
Counter("aab") + Counter("bcc")  # Counter({'b': 2, 'a': 2, 'c': 2})
Counter("aab") - Counter("ab")   # Counter({'a': 1})

유용한 패턴

# 중첩 딕셔너리 안전 접근
d = {"a": {"b": {"c": 1}}}
d.get("a", {}).get("b", {}).get("c")  # 1
d.get("x", {}).get("y", {}).get("z")  # None

# 조건부 키 존재시 처리
if "key" in d:
    value = d["key"]
# 또는
value = d.get("key")
if value is not None:
    pass

# 딕셔너리 정렬
d = {"c": 3, "a": 1, "b": 2}

# 키 기준 정렬
dict(sorted(d.items()))              # {'a': 1, 'b': 2, 'c': 3}

# 값 기준 정렬
dict(sorted(d.items(), key=lambda x: x[1]))

# 역정렬
dict(sorted(d.items(), reverse=True))

# 딕셔너리 뒤집기 (키↔값)
{v: k for k, v in d.items()}

# 여러 딕셔너리에서 공통 키 찾기
a = {"x": 1, "y": 2}
b = {"y": 3, "z": 4}
common_keys = a.keys() & b.keys()    # {'y'}

# 딕셔너리 값으로 필터링
{k: v for k, v in d.items() if v > 1}