Python / LESSON 07 / PY07

Python:辞書と集合

1学習の目的

2基礎解説

やりたいこと書き方意味
辞書を作るd = {"name": "田中", "age": 30}キー:値 のペアで持つ
取り出すd["name"] / d.get("age")番号ではなく名前で引く
追加・更新d["dept"] = "営業"無ければ追加、あれば上書き
集合を作るs = set([1, 2, 2, 3])重複が自動で消える・順序なし
✅ 覚えるべき重要ポイント
  1. 辞書は {キー: 値}番号ではなく名前で引けるのがリストとの決定的な違い。順序ズレの事故が起きない。
  2. 存在しないキーを d["x"] で引くと KeyErrord.get("x") なら None、d.get("x", 0) なら既定値が返る。
  3. 追加も更新も d["キー"] = 値 と書き方は同じ。キーの有無で自動的に切り替わる。
  4. ループは for key, value in d.items():。キーだけなら d.keys()、値だけなら d.values()
  5. 集合は set(リスト)重複を一発で除去できる。順序は保証されないので、順番が必要なら sorted() でリストに戻す。

現場使用例:APIのJSON応答 res["data"]["items"]、設定値の管理、商品ごとの売上集計、重複ユーザーIDの除去 set(ids)

person = {"name": "田中", "age": 30}

print(person["name"])                 # 田中
print(person.get("dept", "未設定"))   # 未設定(キーが無くても安全)

person["dept"] = "営業"   # 追加
person["age"] = 31        # 上書き

for key, value in person.items():
    print(f"{key}: {value}")

# 集合は重複を消す
ids = [3, 1, 3, 2, 1]
print(set(ids))          # {1, 2, 3}
print(sorted(set(ids)))  # [1, 2, 3]

3基本ドリル(10問)

PY07-D01 person = {"name": "田中", "age": 30} から名前と年齢を、この順に1行ずつ出力せよ。 コーディング★☆☆無料
期待される結果

出力 == 田中 / 30(2行)

ヒント

角カッコにキーを文字列で入れる。person["name"] のように書く。

模範解答
person = {"name": "田中", "age": 30}
print(person["name"])
print(person["age"])
解説

リストは番号、辞書はキーで引く。person[0] とは書けない点に注意。

PY07-D02 d = {"a": 1} のとき d["b"] を実行するとどうなるか。
A. None が返る B. KeyErrorになる C. 0 が返る D. 空文字が返る
選択★☆☆無料
期待される結果

解答 == B

ヒント

存在しないキーを角カッコで引いたときの挙動。

模範解答
B
解説

存在しないキーはエラーで止まる。落としたくない場面では get() を使い分ける。

PY07-D03 prices = {"りんご": 150} に「みかん」=100 を追加し、辞書全体を出力せよ。 コーディング★☆☆無料
期待される結果

出力 == {'りんご': 150, 'みかん': 100}

ヒント

prices["みかん"] = 100 と書くだけで追加される。

模範解答
prices = {"りんご": 150}
prices["みかん"] = 100
print(prices)
解説

リストの append にあたる操作。辞書は代入するだけで追加できる。

PY07-D04 キー "dept" が無くても「未設定」と表示されるようコードを完成させよ。 穴埋め★☆☆無料
コード
d = {"name": "田中"}
print(d.____("dept", "未設定"))
期待される結果

出力 == 未設定

ヒント

既定値つきで安全に取り出すメソッド。

模範解答
print(d.get("dept", "未設定"))
解説

get(キー, 既定値) はデータの欠損に強い書き方。実務のJSON処理ではほぼこちらを使う。

PY07-D05 set([1, 2, 2, 3, 3, 3]) の要素数はいくつか。
A. 6 B. 3 C. 1 D. エラーになる
選択★☆☆無料
期待される結果

解答 == B

ヒント

集合の最大の特徴を思い出す。

模範解答
B
解説

重複が消えて {1, 2, 3} の3個になる。「何種類あるか」を数えるときの定番。

PY07-D06 scores = {"佐藤": 82, "鈴木": 95} の中身を「佐藤:82点」の形式で1行ずつ出力せよ。 コーディング★★☆無料
期待される結果

2行。佐藤:82点 / 鈴木:95点

ヒント

for name, score in scores.items(): で キーと値を同時に受け取れる。

模範解答
scores = {"佐藤": 82, "鈴木": 95}
for name, score in scores.items():
    print(f"{name}:{score}点")
解説

items() を付け忘れるとキーだけが回る。値も欲しいときは必ず items()。

PY07-D07 辞書 d に "age" というキーが存在するかを判定するコードを完成させよ。 穴埋め★★☆無料
コード
d = {"name": "田中", "age": 30}
if "age" ____ d:
    print("あり")
期待される結果

出力 == あり

ヒント

PY06でリストにも使った「含まれるか」の演算子。

模範解答
if "age" in d:
解説

辞書に in を使うとキーを探す(値ではない)。KeyError を防ぐ事前チェックとして使える。

PY07-D08 d = {"a": 1} に対して d["a"] = 5 を実行するとどうなるか。
A. エラーになる B. 値が5に上書きされる C. {"a":1, "a":5} になる D. 無視される
選択★★☆無料
期待される結果

解答 == B

ヒント

同じキーは重複して持てるか?

模範解答
B
解説

キーは重複できない。同じキーへの代入は常に上書き。これを利用して「最新の値で更新する」処理が書ける。

PY07-D09 ids = [3, 1, 3, 2, 1] から重複を除き、小さい順のリストとして出力せよ。 コーディング★★☆無料
期待される結果

出力 == [1, 2, 3]

ヒント

set() で重複を消し、sorted() で並べ替える。1行で書ける。

模範解答
ids = [3, 1, 3, 2, 1]
print(sorted(set(ids)))
解説

PY06のS04では not in と append で4行かけた処理が1行になる。道具を知っているかどうかで差が出る典型例。

PY07-D10 orders = ["A", "B", "A", "C", "B", "A"] の出現回数を辞書で数え、辞書をそのまま出力せよ。 コーディング★★☆無料
期待される結果

出力 == {'A': 3, 'B': 2, 'C': 1}

ヒント

空の辞書 count = {} を用意し、count[o] = count.get(o, 0) + 1 で数え上げる。

模範解答
orders = ["A", "B", "A", "C", "B", "A"]

count = {}
for o in orders:
    count[o] = count.get(o, 0) + 1

print(count)
解説

get(キー, 0) + 1 は集計の最重要イディオム。「初回は0から、2回目以降は加算」を1行で表現できる。ここは丸暗記してよい。

4実践シナリオ(5問)

PY07-S01 【社員情報の表示】employee = {"name": "田中", "dept": "営業", "age": 30} の全項目を「name: 田中」の形式で出力し、最後に「項目数:3」と出力せよ。 コーディング★★☆無料
期待される結果

3行の項目+最終行 項目数:3

ヒント

items() で回す。項目数は len(employee)。

模範解答
employee = {"name": "田中", "dept": "営業", "age": 30}

for key, value in employee.items():
    print(f"{key}: {value}")

print(f"項目数:{len(employee)}")
解説

辞書の len() はキーの個数を返す。APIから受け取ったデータの中身をとりあえず全部見たいときにこの形をよく使う。

PY07-S02 【成績表・辞書版】scores = {"佐藤": 82, "鈴木": 95, "高橋": 67} を「佐藤:82点」の形式で出力し、最後に「平均:81.3点」と小数1桁で出力せよ。 コーディング★★☆無料
期待される結果

3行の成績+最終行 平均:81.3点

ヒント

平均は sum(scores.values()) / len(scores)。値だけの合計が必要なので values() を使う。

模範解答
scores = {"佐藤": 82, "鈴木": 95, "高橋": 67}

for name, score in scores.items():
    print(f"{name}:{score}点")

average = sum(scores.values()) / len(scores)
print(f"平均:{average:.1f}点")
解説

PY06のS02では names と scores の2本を番号でひも付けたが、辞書なら1本で完結し順序ズレも起きない。同じ問題の改良版として見比べてほしい。

PY07-S03 【在庫チェック】stock = {"ボールペン": 120, "ノート": 8, "付箋": 67}、threshold = 10。在庫が threshold 未満の商品を「⚠ノート:8個」の形式で出力し、最後に「要発注:1品目」と出力せよ。 コーディング★★☆無料
期待される結果

該当1件を出力後、最終行 要発注:1品目

ヒント

items() で回して if で判定。カウンタはループの前に用意する。

模範解答
stock = {"ボールペン": 120, "ノート": 8, "付箋": 67}
threshold = 10

count = 0
for name, num in stock.items():
    if num < threshold:
        print(f"⚠{name}:{num}個")
        count += 1

print(f"要発注:{count}品目")
解説

PY06の在庫レポートを辞書で書き直した形。商品名と在庫数が1つにまとまっているので、index で引く必要がなくなった。

PY07-S04 【商品別売上集計】sales = [("A", 1200), ("B", 800), ("A", 500), ("C", 300), ("B", 1000)] から商品ごとの合計を求め、「A:1,700円」の形式で出力し、最後に「合計:3,800円」と出力せよ。 コーディング★★★無料
期待される結果

商品別3行+最終行 合計:3,800円

ヒント

空の辞書を用意し、totals[name] = totals.get(name, 0) + amount で足し込む。総合計は sum(totals.values())。

模範解答
sales = [("A", 1200), ("B", 800), ("A", 500), ("C", 300), ("B", 1000)]

totals = {}
for name, amount in sales:
    totals[name] = totals.get(name, 0) + amount

for name, amount in totals.items():
    print(f"{name}:{amount:,}円")

print(f"合計:{sum(totals.values()):,}円")
解説

D10の数え上げを加算に変えただけで売上集計になる。タプルのリスト(PY06)+辞書集計(PY07)の合わせ技で、実務のデータ処理の大半がカバーできる。

PY07-S05 【受講者の集合演算】python_users = {"佐藤", "鈴木", "高橋", "田中"}sql_users = {"鈴木", "田中", "伊藤"} から、両方受講している人・Pythonのみの人・受講者総数を3行で出力せよ。
名前は五十音ではなく sorted() の順で読点区切りにすること。
コーディング★★★無料
期待される結果

出力3行が完全一致

ヒント

集合同士は &(共通)、-(差)、|(和)で計算できる。名前の並びを固定するため sorted() を通す。

模範解答
python_users = {"佐藤", "鈴木", "高橋", "田中"}
sql_users = {"鈴木", "田中", "伊藤"}

both = sorted(python_users & sql_users)
only_python = sorted(python_users - sql_users)
all_users = python_users | sql_users

print(f"両方受講:{len(both)}人({'、'.join(both)})")
print(f"Pythonのみ:{len(only_python)}人({'、'.join(only_python)})")
print(f"受講者総数:{len(all_users)}人")
解説

集合演算はベン図がそのままコードになる。「両方のリストに入っている人」をループで探すと二重ループになるが、& なら1文字で済む。

5仕上げ課題

PY07-FINAL 【アンケート集計レポート】地域と評価のペアから、2種類の集計を出力するスクリプトを書け。
responses = [
  ("東京", "満足"), ("大阪", "普通"), ("東京", "満足"),
  ("福岡", "不満"), ("大阪", "満足"), ("東京", "普通"), ("東京", "満足")
]


仕様:
① 地域別の件数を「東京:4件」の形式で出力([地域別] の見出し付き)
② 評価別の件数を同じ形式で出力([評価別] の見出し付き)
③ どちらも最初に登場した順で並べること
④ 回答数と地域数、満足率(小数1桁)を出力

出力仕様(12行):
=== アンケート集計 ===
[地域別]
東京:4件
大阪:2件
福岡:1件
[評価別]
満足:4件
普通:2件
不満:1件
---
回答数:7件 / 地域数:3
満足率:57.1%
期待される結果

出力12行が完全一致

ヒント

地域用と評価用の空の辞書を2つ用意し、1回のループで両方を get(キー, 0) + 1 で数え上げる。Pythonの辞書は追加した順を保つので、並べ替えは不要。満足率は 満足の件数 / 回答数 * 100。

模範解答
responses = [
    ("東京", "満足"), ("大阪", "普通"), ("東京", "満足"),
    ("福岡", "不満"), ("大阪", "満足"), ("東京", "普通"), ("東京", "満足")
]

area_count = {}
rating_count = {}

for area, rating in responses:
    area_count[area] = area_count.get(area, 0) + 1
    rating_count[rating] = rating_count.get(rating, 0) + 1

print("=== アンケート集計 ===")

print("[地域別]")
for area, num in area_count.items():
    print(f"{area}:{num}件")

print("[評価別]")
for rating, num in rating_count.items():
    print(f"{rating}:{num}件")

rate = rating_count["満足"] / len(responses) * 100

print("---")
print(f"回答数:{len(responses)}件 / 地域数:{len(area_count)}")
print(f"満足率:{rate:.1f}%")
解説

1回のループで2つの軸を同時に集計するのが要点。データを2周する必要はない。Python 3.7以降の辞書は挿入順を保つので、登場順の出力がそのまま実現できる。これはExcelのピボットテーブルに相当する処理で、ここが書ければ集計業務はほぼ自動化できる。