Pythonの順序付き辞書OrderedDictの使い方

Pythonの辞書(dict型オブジェクト)は要素の順番を保持しない。CPythonは3.6から順番を保持しているが、実装依存なのでそのほかの実装では不定。3.7から言語仕様で順番を保持するようになる(らしい)。 標準ライブラリのcollectionsモジュールに順番が保持された辞書としてOrderedDictが用意されています。こちらを使っておけば安心。

8.3. collections OrderedDict — コンテナデータ型 — Python 3.6.5 ドキュメント

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)など)のシーケンスなどが使えます。後者はキーと値のペアであればリストでもタプルでも問題ありません。

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)])

バージョン3.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)])

詳細は

要素を先頭・末尾に移動

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)])
Last Updated: 6/26/2019, 10:34:03 PM