Q1次のうち正しく set を作れているのはどれですか?
集合型 (set) の使い方
Python の集合型 set を基礎から解説します。重複なし・順序なしの特徴、要素操作、集合演算、実用パターンまで一通り図解で押さえます。
set とは — 重複なし・順序なし
集合 (set) は、リストやタプルと同じく複数の値をまとめるための型ですが、2 つだけ大きく違うルールがあります。
- 同じ値は 1 つだけしか持てない(重複を自動で取り除く)
- 順序を保持しない(並びに意味がない)
同じ値を入れても、重複は削除され 1 つしか残りません。
(この例では a が 1 つになっています)
{ と } で囲んで、カンマ区切りで値を並べて宣言します。
空の集合を作りたいときは {} ではなく set() を使ってください。{} だと空の辞書になります。
# 重複は自動で消える
set_a = {"a", "b", "c", "d", "a"}
print(set_a) # {'a', 'b', 'c', 'd'}(順番は環境によって変わる)
print(type(set_a)) # <class 'set'>
print(len(set_a)) # 4(重複した 'a' は 1 つにまとまる)
# 数値や混在型もOK
mixed = {1, "apple", 3.14}
# 空の集合は set() を使う
empty_set = set()
empty_dict = {} # こちらは「空の辞書」になる
print(type(empty_set)) # <class 'set'>
print(type(empty_dict)) # <class 'dict'>
# 含まれているかの確認は in / not in
print("a" in set_a) # True
print("z" not in set_a) # True
順序がないので、インデックスでは取り出せない
set は順序を持たないため、set_a[0] のようなインデックスアクセスはできません(TypeError になります)。「○番目の要素を取りたい」場合は、list か tuple に変換してから取り出してください。「並びに意味があるなら list / tuple、無いなら set」 と用途で選び分けましょう。
要素の追加と削除
set はミュータブル(変更可能)な型なので、宣言したあとに要素を追加・削除できます。
よく使うメソッドは次の 5 つです。
| メソッド | 役割 | ポイント |
|---|---|---|
| add(x) | 要素 x を追加 | 既にあれば何もしない(重複は無視) |
| remove(x) | 要素 x を削除 | x が無ければ KeyError |
| discard(x) | 要素 x を削除 | x が無くてもエラーにならない |
| pop() | 任意の要素を 1 つ取り出して削除 | どれが取り出されるかは決まらない |
| clear() | 全要素を削除 | 空の set になる |
fruits = {"apple", "banana", "lemon"}
# 追加
fruits.add("grape")
fruits.add("apple") # 既にあるので無視される
print(fruits) # {'apple', 'banana', 'lemon', 'grape'}
# 削除(remove は無いとエラー)
fruits.remove("banana")
# fruits.remove("melon") # KeyError
# discard は無くてもエラーにならない
fruits.discard("melon") # 何も起きない
print(fruits) # {'apple', 'lemon', 'grape'}
# 任意の要素を取り出して削除
picked = fruits.pop()
print(picked) # どれか 1 つ(実行ごとに変わる)
# 全部空にする
fruits.clear()
print(fruits) # set()
「無いはずの値が紛れ込んでいたら気付きたい」 ときは remove(エラーで知らせる)。
「あれば消したいだけ、無くても気にしない」 ときは discard。
集合演算 — 和集合・積集合・差集合・対称差
set の最大の機能が集合演算です。2 つの集合を組み合わせて、共通する要素やどちらか片方にしかない要素を一度に取り出せます。リストでも for 文で書けば同じことはできますが、set ははるかに速く処理ができます。
- 和集合(union) — どちらか一方でも含まれている要素を全部
- 積集合(intersection) — 両方に含まれている要素だけ
- 差集合(difference) —
sにあってtにない要素 - 対称差(symmetric_difference) — どちらか片方にしかない要素
以下の図は、s = {a, b, c, d}、t = {c, d, e, f} のときの結果です。
演算子(| & - ^) と メソッド(union など) はどちらを使ってもよいです。
s = {"a", "b", "c", "d"}
t = {"c", "d", "e", "f"}
# 和集合
print(s | t) # {'a', 'b', 'c', 'd', 'e', 'f'}
print(s.union(t)) # 同じ
# 積集合
print(s & t) # {'c', 'd'}
print(s.intersection(t)) # 同じ
# 差集合(s に含まれて t に含まれないもの)
print(s - t) # {'a', 'b'}
print(s.difference(t)) # 同じ
# 対称差(どちらか片方にしか無いもの)
print(s ^ t) # {'a', 'b', 'e', 'f'}
print(s.symmetric_difference(t)) # 同じ
部分集合の判定(参考)
a <= b あるいは a.issubset(b) で、「a の要素がすべて b に含まれているか」を True / False で確認できます。逆方向は a >= b や a.issuperset(b)。
用途としては「ユーザーが持っている権限の集合に必須権限の集合がすべて含まれているか」のようなチェックに用います。初めのうちは「集合演算」を優先して覚え、必要になったタイミングで使いましょう。
実用パターン — 重複削除と高速な存在チェック
最後に、実務で本当によく使う 2 つの定番パターンを押さえておきましょう。
list(set(...)) で「いったん set に変換して重複を消し、再度 list に戻す」パターンの利用が多いです。
1 行で書けて速く、for 文で重複判定するより圧倒的に簡潔です。
# パターン①: 重複削除
numbers = [1, 2, 2, 2, 3, 4, 4, 5, 6, 6]
unique_numbers = list(set(numbers))
print(unique_numbers) # [1, 2, 3, 4, 5, 6](順序は環境によって変わる)
# パターン②: 高速な存在チェック
# x in set は、x in list よりずっと速い
allowed_users = {"alice", "bob", "carol"}
print("alice" in allowed_users) # True
print("dan" in allowed_users) # False
なぜ set の in は速いのか
set は内部でハッシュテーブルというデータ構造を使っています。これは「値を計算結果(ハッシュ)から直接探す」仕組みで、要素数が増えてもほぼ一定の時間で見つけられます。
リストの in は先頭から順番に比較していくため、要素数が増えるほど遅くなります。「含まれているかを何度もチェックする」用途なら、最初に set に変換しておくと一気に速くなる、と覚えておくと役立ちます。
この記事では、set の特徴(重複なし・順序なし)、追加と削除のメソッド、集合演算、そして重複削除と高速な存在チェックという実用パターンを学びました。
「並びは要らない、ユニークなものだけが欲しい」「含まれているかを何度も確認したい」「集合の重なりを取りたい」 — このどれかに当てはまったら、set の出番です。
理解度チェック
まずは1問ずつ答えてみましょう。
Q2s = {1, 2, 3} に対して s.discard(99) を実行するとどうなりますか?(99 は含まれていません)
Q3s = {1, 2, 3, 4} と t = {3, 4, 5, 6} のとき、s & t の結果はどれですか?