nikkie-ftnextの日記

イベントレポートや読書メモを発信

小ネタ:Pythonのdictが挿入順序を保存することを利用して、挿入順序を保存したsetを適用する

はじめに

いのりさんのエビフライ😋 nikkieです。

Today(※最近) I learnedです。
※本小ネタは使い所が限定的です

目次

サードパーティパッケージを使わずに、挿入順序を保存したsetはできないか?

Pythondictは(3.7から)挿入順序を保存します。
この機能を、挿入順序を保存したsetのように使う小ネタの紹介です(※後述するように限界があります)

なお、過去の記事でboltonsというサードパーティパッケージを紹介しました。
この記事のような縛りをせずに、パッケージ(推しはboltons)を使うのをオススメします

知ったきっかけは、Stack Overflow。

辞書を使うアイデアがこちら:https://stackoverflow.com/a/53657523
見ていきましょう

dictfromkeys

dictfromkeysというクラスメソッドがありました!
https://docs.python.org/ja/3/library/stdtypes.html#dict.fromkeys
dict.fromkeys(iterable, value)は、

iterable からキーを取り、値を value に設定した、新しい辞書を作成します。

value はデフォルトで None となります。

% uv run --python 3.13.0 python
>>> dict.fromkeys("abcb")
{'a': None, 'b': None, 'c': None}

ここで作っているのは辞書なので、挿入順序が保存されています。
setの場合は、挿入順序ではありません。

>>> set("abcb")
{'a', 'c', 'b'}

dict.fromkeys()を使った、挿入順序を保存したsetの適用

挿入順序を保存、かつ、重複の排除を達成しています。
しかし、挿入順序を保存したsetそのものが得られるわけではありません。

>>> list(set("abcb"))
['a', 'c', 'b']
>>> list(dict.fromkeys("abcb"))  # abcbという順序を保存し、かつ、重複が除かれている
['a', 'b', 'c']

挿入順序を保存したsetに近いのはkeys()メソッド。
上のlist(dict)list(dict.keys())と同じです。

keys()メソッドは、「辞書ビューオブジェクト」なるものを返しています。
https://docs.python.org/ja/3/library/stdtypes.html#dictionary-view-objects
このオブジェクトは集合演算をサポートしていますが、単にsetが返るので挿入順序は保存されなくなります(これが先述の「限界」です)

>>> dict.fromkeys("abcb").keys() - set("bd")
{'a', 'c'}
>>> list(dict.fromkeys("abcb").keys() - set("bd"))
['a', 'c']

>>> dict.fromkeys("abcb").keys() - set("d")  # 挿入順序が保存されないsetが返っている
{'a', 'c', 'b'}
>>> list(dict.fromkeys("abcb").keys() - set("d"))
['a', 'c', 'b']

終わりに

dict.fromkeys()を知りました。
Python 3.7以降の辞書が挿入順序を保存することを利用して、挿入順序を保存したsetを適用できます。

>>> list(dict.fromkeys("abracadabra"))  # 挿入順序を保つ、かつ、重複を除く
['a', 'b', 'r', 'c', 'd']

ただし、挿入順序を保存したsetそのものは得られません。
ユースケースによっては、boltonsをはじめとするサードパーティパッケージをまず検討ください