Pythonの順序付き辞書OrderedDictの使い方
Pythonの辞書(dict
型オブジェクト)は要素の順番を保持しない。CPythonは3.6
から順番を保持しているが、実装依存なのでそのほかの実装では不定。3.7
から言語仕様で順番を保持するようになる(らしい)。
標準ライブラリのcollectionsモジュールに順番が保持された辞書としてOrderedDict
が用意されている。こちらを使っておけば安心。
collectionsモジュールをインポートする。標準ライブラリに含まれているのでインストールする必要はない。
import collections
以下のように書けば、以降の例のcollections.
は省略できる。
from collections import OrderedDict
OrderedDict
の使い方として以下の内容を説明する。
- OrderedDictオブジェクトの作成
- OrderedDictはdictのサブクラス
- 要素を先頭・末尾に移動
- 任意の位置に新たな要素を追加
- 要素を入れ替え(並べ替え)
- 要素をキーまたは値でソート
OrderedDictオブジェクトの作成
コンストラクタcollections.OrderedDict()
でOrderedDict
オブジェクトを作成できる。
空のOrderedDict
オブジェクトを作成して値を追加。
od = collections.OrderedDict()
od['k1'] = 1
od['k2'] = 2
od['k3'] = 3
print(od)
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])
コンストラクタに引数を指定することも可能。
キーワード引数や、キーと値のペアのシーケンス(タプル(key, value)
など)のシーケンスなどが使える。後者はキーと値のペアであればリストでもタプルでもOK。
print(collections.OrderedDict(k1=1, k2=2, k3=3))
print(collections.OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)]))
print(collections.OrderedDict((['k1', 1], ['k2', 2], ['k3', 3])))
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])
Python3.5まではキーワード引数だと順序が保持されていなかったが、3.6から保持されるようになった。
バージョン 3.6 で変更: PEP 468 の受理によって、OrderedDict のコンストラクタと、update() メソッドに渡したキーワード引数の順序は保持されます。
8.3. collections — コンテナデータ型 — Python 3.6.5 ドキュメント
通常の辞書(dict
型オブジェクト)もコンストラクタに渡せるが、dict
型が順序を保持していない実装の場合、それから生成したOrderedDict
も順序を保持しない。
print(collections.OrderedDict({'k1': 1, 'k2': 2, 'k3': 3}))
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])
OrderedDictはdictのサブクラス
OrderedDict
はdict
のサブクラス。
print(issubclass(collections.OrderedDict, dict))
# True
OrderedDict
もdict
と同じメソッドを持っており、要素の取得や変更、追加、削除などの方法はdict
と同じ。
print(od['k1'])
# 1
od['k2'] = 200
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3)])
od.update(k4=4, k5=5)
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3), ('k4', 4), ('k5', 5)])
del od['k4'], od['k5']
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3)])
詳細は以下の記事を参照。
- 関連記事: Pythonで辞書に要素を追加、辞書同士を連結(結合)
- 関連記事: Pythonで辞書の要素を削除するclear, pop, popitem, del
- 関連記事: Pythonの辞書のgetメソッドでキーから値を取得(存在しないキーでもOK)
要素を先頭・末尾に移動
OrderedDict
独自のメソッドmove_to_end()
を使って要素を先頭または末尾に移動できる。
キーを第一引数に指定する。デフォルトは末尾に移動、第二引数last
をFalse
とすると先頭に移動される。
od.move_to_end('k1')
print(od)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1)])
od.move_to_end('k1', False)
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3)])
任意の位置に新たな要素を追加
任意の位置に新たな要素を追加したOrderedDict
オブジェクトを新たに作成できる。
items()
メソッドで取得できるビューオブジェクト をlist()
でリスト化- リストの
insert()
メソッドでキーと値のペアのタプル(key, value)
を追加 - コンストラクタ
collections.OrderedDict()
に渡し、新たなオブジェクトを作成
という流れ。
l = list(od.items())
print(l)
# [('k1', 1), ('k2', 200), ('k3', 3)]
l.insert(1, ('kx', -1))
print(l)
# [('k1', 1), ('kx', -1), ('k2', 200), ('k3', 3)]
od = collections.OrderedDict(l)
print(od)
# OrderedDict([('k1', 1), ('kx', -1), ('k2', 200), ('k3', 3)])
insert()
は第一引数に挿入する位置、第二引数に挿入する要素を指定する。
例では元の変数に新たなオブジェクトを代入しており、元のオブジェクト自体に新たな要素を追加したわけではない。
要素を入れ替え(並べ替え)
要素の入れ替えも上の例と同じ流れ。
items()
メソッドで取得できるビューオブジェクト をlist()
でリスト化- リストの要素を入れ替え
- コンストラクタ
collections.OrderedDict()
に渡し、新たなオブジェクトを作成
l = list(od.items())
print(l)
# [('k1', 1), ('kx', -1), ('k2', 200), ('k3', 3)]
l[0], l[2] = l[2], l[0]
print(l)
# [('k2', 200), ('kx', -1), ('k1', 1), ('k3', 3)]
od = collections.OrderedDict(l)
print(od)
# OrderedDict([('k2', 200), ('kx', -1), ('k1', 1), ('k3', 3)])
キーを指定して入れ替えたい場合は、以下のようにキーのリストからindex()
メソッドでインデックス(位置)を位置を取得する。
l = list(od.items())
k = list(od.keys())
print(k)
# ['k2', 'kx', 'k1', 'k3']
print(k.index('kx'))
# 1
l[k.index('kx')], l[k.index('k3')] = l[k.index('k3')], l[k.index('kx')]
print(l)
# [('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)]
od = collections.OrderedDict(l)
print(od)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)])
もっといいやり方がありそうな気もする。
要素をキーまたは値でソート
items()
メソッドで取得できるビューオブジェクトをもとにソートしたキーと値のペアのタプル(key, value)
のリストを作成、コンストラクタcollections.OrderedDict()
に渡し、新たなオブジェクトを作成する。
組み込み関数sorted()
の引数key
にタプル(key, value)
からキーまたは値を返す無名関数(ラムダ式)を指定してソートする。
逆順にする場合はsorted()
の引数reverse
をTrue
にする。
print(od)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)])
od_sorted_key = collections.OrderedDict(
sorted(od.items(), key=lambda x: x[0])
)
print(od_sorted_key)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3), ('kx', -1)])
od_sorted_value = collections.OrderedDict(
sorted(od.items(), key=lambda x: x[1], reverse=True)
)
print(od_sorted_value)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)])