nikkie-ftnextの日記

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

Pythonで挿入順序を保存したsetで、メンテされているものをください(2025年1月時点で見つけたのは、boltons)

はじめに

あるよ。」nikkieです。

PyPIを探したら簡単に見つかると思ったのですが、存外時間がかかったので備忘録にします。
「メンテされている」が狭き門でしたね。

目次

挿入順序を保存したsetがほしい!

まずPythonは、3.7から辞書(dict)が挿入順序を保存します。
https://docs.python.org/ja/3/whatsnew/3.7.html#summary-release-highlights

dict オブジェクトの挿入順序を保存するという性質が、公式に Python 言語仕様の一部であると 宣言されました (「Python のデータモデルの改善」より)

3.6以前で挿入順序を保存した辞書を使いたい場合、collections.OrderedDictがあったという理解です。
https://docs.python.org/ja/3/library/collections.html#ordereddict-objects

組み込みの dict クラスが挿入順序を記憶しておく機能 (略) を獲得した今となっては、順序付き辞書の重要性は薄れました。

重要性は薄れた」とありますが、挿入順序を保存したdictOrderedDictと同じものではなく、OrderedDictは並べ替え操作に向くようです。

OrderedDict のアルゴリズムは、頻繁な並べ替え処理を dict よりもうまく扱うことができます。

今回は、3.7以降のdictcollections.OrderedDictのset版、挿入順序が保存されたset(集合)が欲しくなりました。
標準ライブラリにはないという認識なので、PyPIで探していきました(最初はすぐ見つかるだろうと思っていたんですよね)

結論:あるよ。

boltonsを使うのです。
Awesome PythonのMiscellaneousにも載っていますよ。

https://pypi.org/project/boltons/

% uv run --python 3.13 --with boltons python
>>> # Python 3.13.0, boltons 24.1.0 です
>>> from boltons.setutils import IndexedSet
>>> IndexedSet("abcb")
IndexedSet(['a', 'b', 'c'])
>>> IndexedSet("abcb") - set("db")
IndexedSet(['a', 'c'])
>>> IndexedSet("abcb") - set("d")
IndexedSet(['a', 'b', 'c'])

以下はboltonsにたどり着くまでの過程です

メンテされている、挿入順序を記憶したsetのライブラリ探し

まずPyPIを「orderedset」で検索すると、いっぱい出てきます。
https://pypi.org/search/?q=orderedset
ひとつひとつ見ていくのは骨が折れそうだったので、ググって上位の記事から辿ることにしました。

Pythonのdiscussから

https://discuss.python.org/t/add-orderedset-to-stdlib/12730/3 より

どちらもメンテされていると思えなかったので不採用です

ordered-set(最終リリース 2022年1月)

使用例から、挿入順を記憶する機能を持ったsetと見受けましたが、

>>> letters = OrderedSet('abracadabrashazam')
>>> letters
OrderedSet(['a', 'b', 'r', 'c', 'd', 'x', 's', 'h', 'z', 'm'])
>>> letters -= 'abcd'
>>> letters
OrderedSet(['r', 'x', 's', 'h', 'z', 'm'])

PyPIへのリリースは2022年1月が最後。
GitHub(200 star)はpatchのプルリクエストが取り込まれているようですが、PyPIへのリリースは止まってしまっています

orderedset(最終リリース 2020年2月)

使用例から、挿入順を記憶する機能を持ったsetと見受けましたが、

>>> OrderedSet([1, 2, 3]) | [5, 4, 3, 2, 1]
OrderedSet([1, 2, 3, 5, 4])

PyPIへのリリースは2020年2月が最後。
GitHub(70 star)も同時期に更新が止まっています

Stack Overflowから

上記のdiscussからもリンクされており、検索も上位に出てきた質問

insertion-order preserving set」について、PyPIのパッケージを紹介する回答 https://stackoverflow.com/a/23225031 より

collections-extendedはメンテされていると思えなかったので不採用です

collections-extended(最終リリース 2022年1月)

これは使用例から欲しいものかがパッと分かっていません。
setlistの差集合の例が見つかりませんでした(要・素振り)

PyPIへのリリースは2022年1月が最後。
GitHub(40 star)も同じ年に更新が止まっています

Awesome Pythonから

途中で「Awesome Pythonで紹介されてるんじゃない?」と思い見てみました。
Algorithms and Design Patterns

sortedcontainers - Fast and pure-Python implementation of sorted collections.

お!

sortedcontainers(最終リリース 2022年1月)

https://pypi.org/project/sortedcontainers/

使用例からSortedSetがそれっぽいですが、差集合の例は見つかりませんでした(要・素振り)

PyPIへのリリースは2022年1月が最後。
GitHub(3600 star)は動きがありますが、「それをPyPIへリリースしてくり〜。頼む〜🙏」という気持ちです

メンテされていると思えなかったので不採用です

終わりに

Pythonで挿入順序を保存したsetで、メンテされているライブラリとして私が今回見つけたのはboltonsです。
挿入順序を保存したset以外にも色々と提供してそうで、boltonsは仲良くなりたいパッケージですね。

それにしても、Pythonコミュニティ、挿入順序を保存したsetのパッケージを作りすぎてますね。
私はTwitterのいいねのように結構軽率にstarしていくのですが、メンテされていないと判断したパッケージにstarするのは控えようかなと今回思いました