Python: コンテナ比較と包括的な内包表記
最終更新:2026-09-22
リスト、タプル、辞書、セットを個別に学んできました。今回は横並びで比較します——それぞれの違いは何か、いつどれを使うべきか。また、Python の最も強力な機能の 1 つである内包表記も徹底的にマスターします。
1. 4 つのコンテナの比較
| 機能 | リスト(list) |
タプル(tuple) |
辞書(dict) |
セット(set) |
|---|---|---|---|---|
| 構文 | [] |
() |
{key: value} |
{} または set() |
| 順序付け | ✅ あり | ✅ あり | ✅ 挿入順(3.7+) | ❌ なし |
| ミュータブル | ✅ | ❌ | ✅ | ✅ |
| 重複 | ✅ 許可 | ✅ 許可 | キーは一意、値は重複可能 | ❌ ユニーク |
| アクセス | インデックス [0] |
インデックス [0] |
キー ["key"] |
インデックス不可 |
| 検索速度 | O(n) 低速 | O(n) 低速 | O(1) 非常に高速 | O(1) 非常に高速 |
| 典型的な用途 | 順序データ、動的コレクション | 固定データ、関数の戻り値 | マッピング、キャッシュ | 重複除去、集合演算 |
💡 重要な選択原則: 1)位置によるアクセスが必要 → リスト/タプル。2)名前によるアクセスが必要 → 辞書。3)重複除去や集合演算が必要 → セット。4)データが変更されない → タプル。
▶ サンプル:コンテナ選択の比較(難易度 ⭐⭐)
▶ 試してみよう出力:
TEXT
📖 参照専用
# 执行成功
2. 高度なリスト内包表記
レッスン 11 では基本的な内包表記を学びました。さらに深く掘り下げましょう。
(1) 複数条件
PYTHON
numbers = range(1, 31)
# 3 で割り切れ、かつ 5 で割り切れる
filtered = [n for n in numbers if n % 3 == 0 and n % 5 == 0]
print(filtered) # [15, 30]
# 3 で割り切れる、または 5 で割り切れる
filtered = [n for n in numbers if n % 3 == 0 or n % 5 == 0]
print(filtered) # [3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24, 25, 27, 30]
(2) ネストしたループの内包表記
PYTHON
# 座標ペアを生成 — 二重 for ループに相当
pairs = [(x, y) for x in range(3) for y in range(3)]
print(pairs)
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
# 条件付きネスト — 和が偶数のペアを見つける
pairs = [(x, y) for x in range(3) for y in range(3) if (x + y) % 2 == 0]
print(pairs)
# [(0, 0), (0, 2), (1, 1), (2, 0), (2, 2)]
(3) 内包表記での if-else
PYTHON
# 内包表記での if-else — 位置が異なることに注意
numbers = [1, 2, 3, 4, 5, 6]
# if のみ(フィルタリング)— 後ろに配置
evens = [n for n in numbers if n % 2 == 0]
# if-else(変換)— 前に配置
result = ["even" if n % 2 == 0 else "odd" for n in numbers]
print(result) # ['odd', 'even', 'odd', 'even', 'odd', 'even']
▶ サンプル:データ変換パイプライン(難易度 ⭐⭐⭐)
▶ 試してみよう出力:
TEXT
📖 参照専用
['Apple', 'Banana', 'Cherry', 'Date']
3. 辞書内包表記
辞書でも内包表記が使えます。構文はリストと似ていますが、{} を使用し、キーと値のペアを指定します:
PYTHON
# 基本的な辞書内包表記
squares = {x: x ** 2 for x in range(5)}
print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 条件付き
even_squares = {x: x ** 2 for x in range(10) if x % 2 == 0}
print(even_squares) # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
# キーとvalueの反転
original = {"a": 1, "b": 2, "c": 3}
reversed_dict = {value: key for key, value in original.items()}
print(reversed_dict) # {1: 'a', 2: 'b', 3: 'c'}
(1) 実践:2 つのリストを辞書にマージ
PYTHON
# 2 つのリストを辞書にマージ
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
result = {names[i]: scores[i] for i in range(len(names))}
print(result) # {'Alice': 85, 'Bob': 92, 'Charlie': 78}
# zip() を使うとよりエレガント
result = {name: score for name, score in zip(names, scores)}
print(result) # {'Alice': 85, 'Bob': 92, 'Charlie': 78}
4. セット内包表記
セット内包表記は {} を使って式のみを記述します(コロンはなし)——辞書内包表記との違いはコロンの有無です:
PYTHON
# セット内包表記 — 自動重複除去
numbers = [1, 2, 2, 3, 3, 3, 4, 5, 5]
unique_squares = {x ** 2 for x in numbers}
print(unique_squares) # {1, 4, 9, 16, 25}
# 条件付き
even_set = {x for x in range(20) if x % 2 == 0}
print(even_set) # {0, 2, 4, 6, 8, 10, 12, 14, 16, 18}
💡 3 つの区別:
[x for x in ...] はリスト——順序付けられ、重複可能。{x: y for x in ...} は辞書——コロンあり。{x for x in ...} はセット——コロンなし、順序なし、重複除去。
▶ サンプル:単語分析(難易度 ⭐⭐⭐)
▶ 試してみよう出力:
TEXT
📖 参照専用
Total words: 18
Unique words: 10
All unique words: ['also', 'but', 'favorite', 'great', 'is', 'javascript', 'love', 'my', 'python', 'i']
5. よくあるユースケース
- データクリーニングパイプライン:リスト内包表記で空の値をフィルタリングし、空白を除去し、フォーマットを 1 行で変換
- 辞書マッピングの反転:辞書内包表記でキーと値を入れ替えて逆引き用に
- 重複除去カウント:セット内包表記でユニーク要素の高速統計
- 条件付きグループ化:if-else 内包表記でデータを 2 つのグループに分割(「合格/不合格」など)
- 座標生成:ネスト内包表記でチェス盤の座標やピクセルグリッドなどを生成
❓ よくある質問
Q リスト内包表記とジェネレータ式の違いは何ですか?
A リスト内包表記
[x for x in range(10)] はすべてのデータを一度にメモリに生成します。ジェネレータ式 (x for x in range(10)) は遅延評価で、一度に 1 つの値——メモリを節約します。大規模データセット(数万以上)ではジェネレータを使用してください。Q どのコンテナを使うか、どうやって決めればよいですか?
A 3 つの質問:① ユニークなキーが必要か?→ 辞書。② 重複除去や集合演算が必要か?→ セット。③ データを変更する必要があるか?→ 変更するならリスト、しないならタプル。ほとんどのシナリオでは、リストと辞書で 90% のユースケースをカバーできます。
📖 まとめ
- リストは順序付けられミュータブル。タプルは順序付けられイミュータブル。辞書はキーと値で高速検索。セットは重複除去と集合演算用
- リスト内包表記:
[expression for variable in iterable if condition] - 辞書内包表記:
{key: value for variable in iterable if condition} - セット内包表記:
{expression for variable in iterable if condition} - ループの後の
ifはフィルタリング用。ループの前のif-elseは変換用 - ネスト内包表記で 2D データを生成できるが、2 レベルを超える場合は通常のループを使用
📝 練習問題
-
基本(難易度 ⭐):リスト内包表記を使って、10 から 50 までの 7 で割り切れるか 7 を含む数をすべて生成してください。ヒント:
orで 2 つの条件を結合。 -
中級(難易度 ⭐⭐):2 つのリスト
keys = ["name", "age", "city"]とvalues = ["Alice", 25, "Beijing"]が与えられたとき、辞書内包表記を使ってマージしてください。ヒント:zip(keys, values)でペアにする。 -
挑戦(難易度 ⭐⭐⭐):「データ分析プログラム」を書いてください。複数の文を含む文字列が与えられたとき、総単語数、ユニーク単語数、最も頻繁な 3 つの単語をカウントして出力します。ヒント:トークン化に
split()、カウントに辞書、上位 3 つにsorted(dict.items(), key=lambda x: x[1], reverse=True)[:3]。