set で重複を除去する
set で重複を除去する とは
set 型を使ってリストから重複要素を取り除く方法を学びます。本レッスンでは、set で重複を除去する の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
set で重複を除去する
Python の set (集合) は 重複しない要素の集まり を表現する型です。リストに同じ要素が紛れ込んでしまった、ユニークな ID だけ取り出したい、A と B の共通要素を取りたい、こんな場面で活躍します。set を覚えると if x not in seen のようなボイラープレートを書く必要がなくなり、コードが一気に短くなります。SQL の DISTINCT に近い感覚で扱える、Python の基本中の基本コレクションです。
setは 順序を保証しません。重複除去の結果を順序付きで返したいなら、sortedを組み合わせるのが定石です。
set とは?
{} の中に , 区切りで値を並べると set リテラル、set() で空セットを作ります。{} だけだと空辞書になるので、空セットは必ず set() と書く点に注意です。
Python
colors = {"red", "blue", "red", "green"}
print(colors) # {'red', 'blue', 'green'} (順序は不定)
print(len(colors)) # 3見て分かるとおり、"red" が重複していてもセットの中では 1 つにまとまります。これは ハッシュ によって自動的に行われ、O(1) で重複判定できる、というのが set の強みです。
よく使う操作
下記のとおりです。
| 操作 | 書き方 | 意味 |
|---|---|---|
| 要素追加 | s.add(x) | x を追加 |
| 要素削除 | s.discard(x) | x を削除 (なくてもエラーなし) |
| 存在チェック | x in s | x があるか |
| 和集合 | a | b | どちらかにある |
| 積集合 | a & b | 両方にある |
| 差集合 | a - b | a にあって b にない |
Python
a = {1, 2, 3}
b = {2, 3, 4}
print(a | b) # {1, 2, 3, 4}
print(a & b) # {2, 3}
print(a - b) # {1}集合演算は数学の集合と同じ感覚で書けます。SQL の UNION INTERSECT EXCEPT を一行で書ける、と思うと魅力が伝わるはずです。
リストから set へ
重複除去の典型パターンは set(lst) です。下記のとおりです。
Python
nums = [1, 2, 2, 3, 3, 3, 4]
unique = set(nums)
print(unique) # {1, 2, 3, 4} (順序は不定)set(リスト) で重複が消える、と覚えるだけ。とはいえ順序が崩れるので、順序を保ったままユニーク化 したい場合は sorted(set(nums)) のような書き方をします。
動きを追ってみる
図のとおり、set で重複を消し、sorted で順序を整える、これがユニーク化の王道。「set には順序がない」「sorted は新しいリストを返す」、この 2 点を覚えれば応用が効きます。
よくある間違い
{}を空セットだと思い込む。{}は空辞書、set()が空セット。リテラルでは要素を 1 つ以上書かないと辞書として解釈されます。setの要素は ハッシュ可能 でなければならない。listやdictは入れられず、TypeErrorになります。tupleなら OK。setのイテレーション順序を頼ってはいけない。順序を扱いたい時は必ずsortedを通しましょう。
setは辞書と同じく ハッシュテーブル ベース。要素数が大きくてもx in sが高速、これがリストの代わりに集合を選ぶ最大の理由です。
frozenset の存在
set は可変ですが、frozenset は 不変な集合 です。辞書のキーや別の set の要素として使いたい時に重宝します。
Python
tags = frozenset({"python", "web"})
lookup = {tags: "Python web チーム"}
print(lookup[frozenset({"python", "web"})]) # Python web チーム用途は限られますが、「set をキーにしたい」状況で frozenset を思い出せると一歩進めます。
setとsortedのコンボは、Python で 重複除去 といえばまず思い出すべき定型句。覚えてしまえば一生もののテクニックです。
重複除去で 順序を保ちたい ときの裏技
Python 3.7 以降、辞書は挿入順を保証します。これを利用すると順序を保ったままユニーク化できます。
Python
nums = [3, 1, 2, 1, 3, 2]
unique_preserve = list(dict.fromkeys(nums))
print(unique_preserve) # [3, 1, 2]dict.fromkeys(seq) は 入力順を保ったまま 重複を除いた辞書を作り、それをリスト化することで「順序維持版のユニーク化」が完成します。シーンに応じて sorted(set(...)) と使い分けましょう。
やってみよう
整数リスト nums を受け取り、重複を除いて昇順で並べたリスト を返す関数 unique_sorted を書いてみましょう。テストを安定させるため、戻り値は 必ずソート済みリスト で返します。sorted(set(nums)) の組み合わせで 1 行です。
よくある質問
Q. set とリストはどう違いますか?
A. set は重複を持たない集合で、要素の追加と存在確認が O(1) と高速です。リストは順序付きで重複を許し、要素の前後関係が意味を持つ場面で使います。重複除去や「含まれているか」判定の高速化が必要なら set が圧倒的に有利です。
Q. set の順序は保証されますか?
A. set は順序が保証されません。順序を保ったまま重複を除去したい場合は dict.fromkeys(items) を使う(Python)か、Set + 配列の組み合わせで管理してください。順序付きで集合演算したい場面は意外と多いので覚えておくと便利です。
Q. set 同士の積集合・和集合はどう書きますか?
A. a & b で積集合、a | b で和集合、a - b で差集合になります。リスト同士の共通要素を求めたいときは set(a) & set(b) で O(n) に高速化できます。文字列もイテラブルなので set('abc') & set('bcd') → {'b', 'c'} のように使えます。
次のレッスン
次は 辞書でグループ化と集計 で、set 型を使ってリストから重複要素を取り除く方法を学びます を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- set で重複除去 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. set で重複除去 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
setで重複除去するsortedで昇順に並べる- 戻り値はリストにする (set のままにしない)
入出力例
test-cases.txt
unique_sorted([1,2,2,3,3,3,4]) → [1,2,3,4]
unique_sorted([5,5,5]) → [5]
unique_sorted([3,1,2,1,3]) → [1,2,3]
unique_sorted([]) → []