辞書とセット

これまでの 2 つのレッスンでは、「位置による」アクセスを行うリストとタプルを学びました。しかし現実の生活では、「名前による」検索をすることがよくあります——単語で辞書を引く、名前で連絡先を探すなどです。辞書(dict) はこれを処理します。セットは数学的な集合演算のためのものです。どちらもデータ処理で非常に便利です。


1. 辞書とは

辞書は波括弧 {} で定義し、コロンで区切られたキーと値のペアのセットを含みます。

PYTHON
# 辞書を定義
student = {
    "name": "Alice",
    "age": 20,
    "city": "Beijing"
}

print(student)               # {'name': 'Alice', 'age': 20, 'city': 'Beijing'}
print(type(student))         # <class 'dict'>
💡 辞書を実際の辞書のように考えてください:「キー」は見出し語で、「値」は定義です。キーを調べると瞬時に対応する値が得られます。辞書のルックアップは非常に高速です——10 エントリでも 100,000 エントリでも、速度はほぼ同じです。

基本的な CRUD 操作

PYTHON
# 辞書を作成
user = {}

# キーと値のペアを追加/変更
user["name"] = "Alice"
user["age"] = 25
print(user)                 # {'name': 'Alice', 'age': 25}

# 既存のキーを変更
user["age"] = 26
print(user)                 # {'name': 'Alice', 'age': 26}

# 値を読み取り
print(user["name"])         # Alice
# print(user["email"])      # KeyError! 存在しないキーはエラー

# get() で安全にアクセス — キーが存在しない場合のデフォルト値を指定
print(user.get("email"))             # None — 見つからない、None を返す
print(user.get("email", "not set"))  # not set — カスタムデフォルト値

# キーと値のペアを削除
del user["age"]
print(user)                 # {'name': 'Alice'}
⚠️ 補足: dict["存在しないキー"]KeyError を発生させます。これを避けるには get() を使います——None または指定したデフォルト値を返します。

例:学生情報管理(難易度 ⭐)

PYTHON
# 学生の完全な情報を辞書に保存
student = {
    "name": "Bob",
    "id": "2024001",
    "scores": {"Chinese": 85, "Math": 92, "English": 78},
    "is_active": True
}

# 基本情報を読み取り
print(f"Name: {student['name']}")
print(f"ID: {student['id']}")

# ネストした辞書から読み取り
math_score = student["scores"]["Math"]
print(f"Math score: {math_score}")

# get() で安全にアクセス
phone = student.get("phone", "not filled")
print(f"Phone: {phone}")
▶ 試してみよう

出力:

TEXT
Name: Bob
ID: 2024001
Math score: 92
Phone: not filled

2. よく使われる辞書メソッド

すべてのキー、値、キーと値のペアを取得

PYTHON
user = {"name": "Alice", "age": 25, "city": "Beijing"}

print(user.keys())      # dict_keys(['name', 'age', 'city'])
print(user.values())    # dict_values(['Alice', 25, 'Beijing'])
print(user.items())     # dict_items([('name', 'Alice'), ('age', 25), ('city', 'Beijing')])

# 辞書を反復する最も一般的な方法
for key, value in user.items():
    print(f"{key} = {value}")

出力:

TEXT
name = Alice
age = 25
city = Beijing

pop() と setdefault()

PYTHON
# pop() — キーに対応する値を削除して返す
user = {"name": "Alice", "age": 25, "city": "Beijing"}
city = user.pop("city")
print(f"Removed city: {city}")      # Removed city: Beijing
print(user)                          # {'name': 'Alice', 'age': 25}

# pop() にデフォルト値を指定でき、KeyError を回避
email = user.pop("email", "no email")
print(email)                         # no email — キーが存在しない、デフォルトを返す

# setdefault() — キーが存在すればその値を返し、存在しなければデフォルトを挿入
user = {"name": "Alice"}
result = user.setdefault("age", 18)
print(user)                          # {'name': 'Alice', 'age': 18}

# キーが既に存在する場合、setdefault は変更しない
result = user.setdefault("name", "Bob")
print(user)                          # {'name': 'Alice', 'age': 18} — 変更なし

update() — 辞書のマージ

PYTHON
# 2 つの辞書をマージ
defaults = {"theme": "light", "lang": "en", "font_size": 14}
custom = {"theme": "dark", "font_size": 16}

defaults.update(custom)    # custom の値が defaults の一致するキーを上書き
print(defaults)            # {'theme': 'dark', 'lang': 'en', 'font_size': 16}

例:単語カウント(難易度 ⭐⭐)

PYTHON
# 文中の単語出現回数をカウント
text = "apple banana apple orange banana apple"

word_count = {}
for word in text.split():
    # 単語が既に辞書にある場合はインクリメント、なければ 1 に設定
    word_count[word] = word_count.get(word, 0) + 1

print(word_count)          # {'apple': 3, 'banana': 2, 'orange': 1}

# items() で出力
for word, count in word_count.items():
    print(f"{word}: {count} times")
▶ 試してみよう

出力:

TEXT
apple: 3 times
banana: 2 times
orange: 1 times

3. 辞書の反復とネスト

辞書を反復する 3 つの方法

PYTHON
user = {"name": "Alice", "age": 25, "city": "Beijing"}

# 方法 1:キーを反復
for key in user:                # for key in user.keys(): と同等
    print(f"{key}: {user[key]}")

# 方法 2:値を反復
for value in user.values():
    print(value)

# 方法 3:キーと値のペアを反復(推奨)
for key, value in user.items():
    print(f"{key} → {value}")

ネストした辞書

PYTHON
# ネストした辞書 — 複数の学生レコードを保存
students = {
    "1001": {"name": "Alice", "scores": [85, 90, 78]},
    "1002": {"name": "Bob", "scores": [92, 88, 95]},
    "1003": {"name": "Charlie", "scores": [76, 85, 82]},
}

# ネストした辞書を反復
for sid, info in students.items():
    name = info["name"]
    avg = sum(info["scores"]) / len(info["scores"])
    print(f"{sid} {name}: Average {avg:.1f}")

出力:

TEXT
1001 Alice: Average 84.3
1002 Bob: Average 91.7
1003 Charlie: Average 81.0

4. セットとは

セットは波括弧 {} または set() で定義します。辞書のように見えますが、値がなくキーだけです。セットの特徴は:ユニークな要素、順序なし

PYTHON
# セットを定義
fruits = {"apple", "banana", "orange", "apple"}    # 重複は自動的に削除される
print(fruits)            # {'orange', 'apple', 'banana'} — 順序は変わる可能性あり

# リストからセットを作成
numbers = set([1, 2, 2, 3, 3, 3])
print(numbers)           # {1, 2, 3} — 重複が削除された

# 空のセットは set() を使用する。{} は空の辞書
empty_set = set()
print(type(empty_set))   # <class 'set'>
💡 セットの最も一般的な用途は重複除去です: list(set(list_name)) で素早く重複を削除できます。ただし、セットは順序なしなので、元の順序は失われます。

セットの基本操作

PYTHON
# 追加と削除
s = set()
s.add("apple")
s.add("banana")
s.add("apple")           # 重複追加は無効
print(s)                 # {'apple', 'banana'}

s.discard("apple")       # 削除。存在しない場合もエラーにならない
print(s)                 # {'banana'}

# s.remove("non_existent")   # KeyError が発生!

5. セット演算

ここでセットの真価が発揮されます——数学的な積集合、和集合、差集合:

PYTHON
a = {1, 2, 3, 4, 5}
b = {4, 5, 6, 7, 8}

# 積集合 — 両方のセットに存在する要素
print(a & b)             # {4, 5}
print(a.intersection(b)) # 同じ

# 和集合 — 両方のセットの全要素(重複なし)
print(a | b)             # {1, 2, 3, 4, 5, 6, 7, 8}
print(a.union(b))        # 同じ

# 差集合 — a にあって b にない要素
print(a - b)             # {1, 2, 3}
print(a.difference(b))   # 同じ

# 対称差 — a または b にあるが両方にはない要素
print(a ^ b)             # {1, 2, 3, 6, 7, 8}

例:ユーザー権限分析(難易度 ⭐⭐⭐)

PYTHON
# ソーシャルプラットフォームのユーザー関係をシミュレート
all_users = {"Alice", "Bob", "Charlie", "Diana", "Eve"}
vip_users = {"Bob", "Diana", "Eve"}
blocked_users = {"Diana"}

# 「VIP ではない一般ユーザー」を見つける
normal_users = all_users - vip_users - blocked_users
print(f"Normal users: {normal_users}")

# 「アクティブな VIP(ブロックされていない)」を見つける
active_vip = vip_users - blocked_users
print(f"Active VIPs: {active_vip}")

# 「ブロックされたユーザーの中で VIP」を見つける
blocked_vip = vip_users & blocked_users
print(f"Blocked VIPs: {blocked_vip}")

# 「通知が必要なすべてのユーザー(VIP + ブロック)」を見つける
notify_users = vip_users | blocked_users
print(f"Users to notify: {notify_users}")
▶ 試してみよう

出力:

TEXT
Normal users: {'Alice', 'Charlie'}
Active VIPs: {'Bob', 'Eve'}
Blocked VIPs: {'Diana'}
Users to notify: {'Bob', 'Diana', 'Eve'}

よくあるユースケース


❓ よくある質問

Q 辞書とリストはいつ使い分ければよいですか?
A 「名前」(キー)でデータを検索する場合は辞書を使います——例えば、ID で学生を検索する場合。単にデータに「順次」アクセスするだけならリストを使います——例えば、ショッピングカート。辞書のルックアップはリストよりもはるかに高速です——大規模データセット(数千項目)ではその差は顕著です。
⚠️ Q:辞書のキーにはどのような制限がありますか?なぜリストはキーにできないのですか? A:辞書のキーはイミュータブルでなければなりません——数値、文字列、タプルが使用できます。リストはミュータブルのため、キーにできません。リストがキーで、その内容が変更されると、辞書はそれを見つけられなくなります。これがタプルがキーにできる理由でもあります——イミュータブルなので安全です。

Q discard()remove() の違いは何ですか?
A remove() は要素が存在しない場合に KeyError を発生させます。discard() は発生させません——存在すれば削除し、存在しなければ何もしません。要素が存在するかどうかわからない場合は、安全のために discard() を使いましょう。

📖 まとめ


📝 練習問題

  1. 基本(難易度 ⭐):自分の個人情報(名前、年齢、都市、趣味)の辞書を作成してください。get() で「job」フィールドを読み取り(なければ「not filled」を返す)。items() ですべてのキーと値のペアを出力してください。

  2. 中級(難易度 ⭐⭐):文 "hello world hello python world hello" が与えられたとき、各単語の出現回数をカウントし、最も頻繁に出現する単語を見つけてください。ヒント:辞書をカウントに使用。最大値を見つけるには max(dict.items(), key=lambda x: x[1]) を使用。

  3. 挑戦(難易度 ⭐⭐⭐):「簡易連絡先管理プログラム」を書いてください。辞書(名前→電話番号)を使用します。以下をサポート:add Alice 13800138000del Alicefind Aliceall(すべて表示)。while True を使用し、exit で終了します。ヒント:コマンドの解析に split() を使用。

100%