Python:辞書と集合
1学習の目的
- 辞書を使って「名前で引ける」データを扱えるようになる。リストの番号ひも付けで起きていた順序ズレの事故がなくなる。
- 集合で重複を一発で除去し、辞書で「項目ごとの集計」を書けるようになる。APIのJSON応答や集計レポートはこの2つでできている。
2基礎解説
| やりたいこと | 書き方 | 意味 |
|---|---|---|
| 辞書を作る | d = {"name": "田中", "age": 30} | キー:値 のペアで持つ |
| 取り出す | d["name"] / d.get("age") | 番号ではなく名前で引く |
| 追加・更新 | d["dept"] = "営業" | 無ければ追加、あれば上書き |
| 集合を作る | s = set([1, 2, 2, 3]) | 重複が自動で消える・順序なし |
- 辞書は {キー: 値}。番号ではなく名前で引けるのがリストとの決定的な違い。順序ズレの事故が起きない。
- 存在しないキーを d["x"] で引くと KeyError。d.get("x") なら None、d.get("x", 0) なら既定値が返る。
- 追加も更新も d["キー"] = 値 と書き方は同じ。キーの有無で自動的に切り替わる。
- ループは for key, value in d.items():。キーだけなら d.keys()、値だけなら d.values()。
- 集合は 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問)
出力 == 田中 / 30(2行)
角カッコにキーを文字列で入れる。person["name"] のように書く。
person = {"name": "田中", "age": 30}
print(person["name"])
print(person["age"])
リストは番号、辞書はキーで引く。person[0] とは書けない点に注意。
A. None が返る B. KeyErrorになる C. 0 が返る D. 空文字が返る 選択★☆☆無料
解答 == B
存在しないキーを角カッコで引いたときの挙動。
B
存在しないキーはエラーで止まる。落としたくない場面では get() を使い分ける。
出力 == {'りんご': 150, 'みかん': 100}
prices["みかん"] = 100 と書くだけで追加される。
prices = {"りんご": 150}
prices["みかん"] = 100
print(prices)
リストの append にあたる操作。辞書は代入するだけで追加できる。
d = {"name": "田中"}
print(d.____("dept", "未設定"))
出力 == 未設定
既定値つきで安全に取り出すメソッド。
print(d.get("dept", "未設定"))
get(キー, 既定値) はデータの欠損に強い書き方。実務のJSON処理ではほぼこちらを使う。
A. 6 B. 3 C. 1 D. エラーになる 選択★☆☆無料
解答 == B
集合の最大の特徴を思い出す。
B
重複が消えて {1, 2, 3} の3個になる。「何種類あるか」を数えるときの定番。
2行。佐藤:82点 / 鈴木:95点
for name, score in scores.items(): で キーと値を同時に受け取れる。
scores = {"佐藤": 82, "鈴木": 95}
for name, score in scores.items():
print(f"{name}:{score}点")
items() を付け忘れるとキーだけが回る。値も欲しいときは必ず items()。
d = {"name": "田中", "age": 30}
if "age" ____ d:
print("あり")
出力 == あり
PY06でリストにも使った「含まれるか」の演算子。
if "age" in d:
辞書に in を使うとキーを探す(値ではない)。KeyError を防ぐ事前チェックとして使える。
A. エラーになる B. 値が5に上書きされる C. {"a":1, "a":5} になる D. 無視される 選択★★☆無料
解答 == B
同じキーは重複して持てるか?
B
キーは重複できない。同じキーへの代入は常に上書き。これを利用して「最新の値で更新する」処理が書ける。
出力 == [1, 2, 3]
set() で重複を消し、sorted() で並べ替える。1行で書ける。
ids = [3, 1, 3, 2, 1] print(sorted(set(ids)))
PY06のS04では not in と append で4行かけた処理が1行になる。道具を知っているかどうかで差が出る典型例。
出力 == {'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問)
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から受け取ったデータの中身をとりあえず全部見たいときにこの形をよく使う。
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本で完結し順序ズレも起きない。同じ問題の改良版として見比べてほしい。
該当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 で引く必要がなくなった。
商品別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)の合わせ技で、実務のデータ処理の大半がカバーできる。
名前は五十音ではなく 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仕上げ課題
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のピボットテーブルに相当する処理で、ここが書ければ集計業務はほぼ自動化できる。