2.

Python セットへの要素追加完全ガイド(add / update / 重複排除 / list との違い / 計算量 / よくある間違い)

編集
この記事の要点
  • セットに 1 件追加するときは add()、複数件まとめて追加するときは update()
  • セットは重複を許さないため、同じ値を add() しても増えない
  • セットには順序の保証がない。挿入順とも値順とも限らない
  • 計算量はいずれも平均 O(1) で、リストの append と同等以上に高速
  • 追加する値はハッシュ可能でなければならない(list や dict は不可、tuple は可)

セットへの要素追加とは

Python のセット(set)は重複を許さないコレクション型です。要素を追加するメソッドは add()(1 件)と update()(複数件)の 2 つが基本です。

add() — 1 件ずつ追加

セット名.add(値)

基本例

s = {"a", "b", "c"}

s.add("d")
print(s)
# {'d', 'b', 'c', 'a'}  ← 順序は保証されない

# 既にある値を追加しても変化なし(エラーにもならない)
s.add("d")
print(s)
# {'d', 'b', 'c', 'a'}

セットは重複を許さないため、同じ値を再度 add() しても集合は変化しません。エラーも出ないので、重複チェックを自前で書く必要がありません。

update() — 複数件まとめて追加

イテラブル(リスト、タプル、セット、文字列、ジェネレータなど)から複数の要素を一度に追加します。

s = {1, 2, 3}

# リストから追加
s.update([4, 5, 6])
print(s)  # {1, 2, 3, 4, 5, 6}

# 複数のイテラブルを同時指定可能
s.update([7, 8], {9, 10}, (11,))
print(s)  # {1, 2, ..., 11}

# 文字列は 1 文字ずつ追加される(要注意)
s = set()
s.update("abc")
print(s)  # {'a', 'b', 'c'}

# 1 つの文字列として追加したいときは add() を使う
s = set()
s.add("abc")
print(s)  # {'abc'}

add と update の違い

メソッド引数用途
add(x)単一の値(ハッシュ可能)1 件追加
update(iter, ...)イテラブル(1 つ以上)複数件まとめて追加
|= 演算子セットupdate と同義(セット同士のみ)
# |= は update と同等
s = {1, 2, 3}
s |= {4, 5}
print(s)  # {1, 2, 3, 4, 5}

追加可能な値(ハッシュ可能性)

セットの要素になれるのはハッシュ可能な不変オブジェクトだけです。可変オブジェクト(list / dict / set)は追加できません。

追加可否
int / float / boolOK
strOK
tuple(中身もハッシュ可能なら)OK
frozensetOK
listNG — TypeError: unhashable type: 'list'
dictNG
setNG(frozenset なら可)
s = set()

s.add((1, 2))       # OK: タプル
s.add(frozenset({1, 2}))  # OK: frozenset

s.add([1, 2])       # NG: TypeError
s.add({"a": 1})     # NG: TypeError

順序は保証されない

セットには順序がありませんprint() したときの並びは、ハッシュ値や挿入順に依存し、実行ごとに変わる可能性もあります。

s = set()
s.add("a")
s.add("b")
s.add("c")
print(s)  # 順序は保証されない

# 順序が必要なら sorted で取り出す
print(sorted(s))  # ['a', 'b', 'c']

list との性能比較

操作listset
追加O(1)(append)O(1) 平均
存在チェック(in)O(n)O(1) 平均
重複を許すはいいいえ
順序保証はいいいえ
添字アクセスはいいいえ

重複を排除したい」「含まれているか頻繁に調べたい」用途では set の方が圧倒的に速いです。たとえば「1 万件のユーザー ID から重複を除く」処理では、set 化が定石です。

ids = ["u1", "u2", "u1", "u3", "u2", "u4"]

unique = set(ids)
print(unique)  # {'u1', 'u2', 'u3', 'u4'}

# 順序を保ちつつ重複排除(Python 3.7+ の dict 仕様を利用)
unique_ordered = list(dict.fromkeys(ids))
print(unique_ordered)  # ['u1', 'u2', 'u3', 'u4']

add の戻り値

add()update()戻り値は Noneです。リスト内包表記の中で {s.add(x) for x in ...} としても期待した動作になりません(None だけのセットになる)。

# 悪い例
s = set()
{s.add(x) for x in [1, 2, 3]}
print(s)  # {1, 2, 3}  動くが None のセットを作る副作用ありで非推奨

# 良い例
s = set()
s.update([1, 2, 3])
print(s)  # {1, 2, 3}

# 最良: 内包表記で直接セット作成
s = {x for x in [1, 2, 3]}
print(s)  # {1, 2, 3}

discard / remove との対比

追加とは逆に、削除には remove()(無いとエラー)と discard()(無くてもエラーなし)があります。add は重複してもエラーにならない非対称さがあります。

FAQ

Q: タプルをまとめて追加するときの落とし穴は?
A: s.update((1, 2, 3)) は要素 3 個が追加されます。タプル自体を 1 要素として追加したいなら s.add((1, 2, 3))

Q: スレッドセーフ?
A: CPython の GIL 下では単純な add は概ね安全ですが、複数操作を一連で扱うなら threading.Lock を使うのが無難です。

Q: 順序付きセットはある?
A: 標準ライブラリにはありません。OrderedDict や dict.fromkeys で代替するか、sortedcontainers.SortedSet などサードパーティを使います。

関連

  • セット — 親カテゴリ
  • remove / discard / pop — 要素削除
  • union / intersection / difference — 集合演算
  • frozenset — 変更不可なセット
  • list / dict / tuple — 他の組み込みコレクション
編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. セットの作成
  2. 要素の追加
  3. 要素の削除

最近更新/作成されたページ