Pythonで辞書型のデータを使っている時にキーや値を取得すること、items()などを使ってfor文を回して処理をすることがあると思います。
辞書型はデータの中の要素の順序は保証しません。ですので1から順番に要素を追加したとしても取り出す時に必ず1から順番に取得できるとは限りません。
それを知らずに順番通りになっている想定で実装を進めて、想定外の処理結果になったりして困った経験をしたことがある人も多いのではないでしょうか?
ですが今回紹介するOrderedDictは辞書型のデータの要素の順番を保証してくれます。そのため順番を保証すべき場面では通常のDict型ではなくて、OrderedDictを使うことで想定している処理を行うことができます。
Pythonの順序付き辞書(OrderedDict)の使い方
OrderedDictは辞書型のサブクラスになります。ですので基本的な操作方法は辞書型と同じです。
辞書型の基本的な使い方は以下の記事を参考にしてください。
OrderedDictの作成方法
OrderedDictオブジェクトの作成方法には以下の5つのパターンがあります。
空のOrderedDictオブジェクトを作成する方法
まずは空のOrderedDictオブジェクトを作成する方法です。
要素を持たない空のOrderedDictオブジェクト作成したい時に使います。
作成の際は以下のように書きます。
from collections import OrderedDict
# create simple OrderedDict object
od_1 = OrderedDict()
print(od_1)
# OrderedDict()
こうすることで要素を持たない空のOrderedDictオブジェクトを作成することができます。
キーワード引数を使ってOrderedDictオブジェクトを作成する方法
続いてキーワード引数を使ってOrderedDictオブジェクトを作成する方法です。
指定した要素を持ったOrderedDictオブジェクトを作成したい時に使います。
手前に書いた引数から順序を保ってOrderedDictオブジェクトが作成されます。
作成の際は以下のように書きます。
from collections import OrderedDict
# キーワード引数を使って作成する
od_2 = OrderedDict(hoge=5, fuga=True, pege='string', puga=None)
print(od_2)
# OrderedDict([('hoge', 5), ('fuga', True), ('pege', 'string'), ('puga', None)])
OrderedDictオブジェクト作成の際に任意のキーと値を渡すことで、任意の要素を持ったOrderedDictオブジェクトを作成することができます。
リストを使ってOrderedDictオブジェクトを作成する方法
続いてはリストを使ってOrderedDictオブジェクトを作成する方法です。
リストの順番をそのまま保持してOrderedDictオブジェクトが作成されます。
実際の現場ではリストから作成することが非常に多いと思います。
リストから作成すれば要素数が変化した場合や要素の順番が入れ変わった場合でも柔軟に対応できるからです。
作成の際は以下のように書きます。
from collections import OrderedDict
# 要素としてリストを持ったリストを引数として渡す
list_1 = [['hoge', 10], ['fuga', 20], ['pege', 30]]
od_3 = OrderedDict(list_1)
print(od_3)
# OrderedDict([('hoge', 10), ('fuga', 20), ('pege', 30)])
# 要素としてタプルを持ったリストを引数として渡す
list_2 = [('hoge', 100), ('fuga', 300), ('pege', 0)]
od_4 = OrderedDict(list_2)
print(od_4)
# OrderedDict([('hoge', 100), ('fuga', 300), ('pege', 0)])
引数として渡すリストが持つ要素は、リストでもタプルでも問題ありません。
ただし引数として渡すリストが持つ要素は全て(キー, 値)で構成されたリストもしくはタプルである必要があります。
それ以外の要素を持っているとValueErrorが発生します。
要素の1番目がキーに、2番目が値になるのでその順序だけ間違えないようにしてください。
ちなみに同じキーを持つ要素を渡した場合は後に渡された要素で上書きされていきます。
from collections import OrderedDict
# 同じキーを持った要素がある場合は順番が後ろにあるもので上書きされる
list_3 = [('hoge', 100), ('hoge', 300), ('pege', 0)]
od_5 = OrderedDict(list_3)
print(od_5)
# OrderedDict([('hoge', 300), ('pege', 0)])
これは余談ですが、一応Set型を引数として渡すことも可能です。
ですがSet型は要素の順序を保持しないため、順序を保証するためのOrderedDictオブジェクトを作成するために使うのには向いていないのでお勧めしません。
from collections import OrderedDict
# Set型を引数に渡すことも可能であるが順序は保証されない
list_5 = {('hoge', 100), ('fuga', 300), ('pege', 0)}
od_7 = OrderedDict(list_5)
print(od_7)
# OrderedDict([('fuga', 300), ('pege', 0), ('hoge', 100)])
上記の結果を見てわかるように順番が保証されません。
OrderedDictオブジェクトの使用目的が順番を保持すること、だと思うのでSet型を使うことは基本的にはないと思いますし、避けるべきだとも思います。
辞書型を使ってOrderedDictオブジェクトを作成する方法
続いては辞書型からOrderedDictオブジェクトを作成する方法です。
これは非常にシンプルで辞書型をOrderedDictオブジェクトに渡せばOKです。
作成の際は下記のように書きます。
from collections import OrderedDict
# 辞書型からOrderedDictオブジェクトを作成する
dict_ = {
'hoge': 1,
'fuga': 2,
'pege': 3
}
od_5 = OrderedDict(dict_)
print(od_5)
# OrderedDict([('hoge', 1), ('fuga', 2), ('pege', 3)])
fromkeysを使ってOrderedDictオブジェクトを作成する方法
全ての要素の初期値を同じにしてOrderedDictオブジェクトを作成しい場合はfromkeysを使うと簡単にできます。
作成の際は以下のように書きます。
from collections import OrderedDict
# Create OrderedDict with fromkeys.
list_6 = ['hoge', 'fuga', 'pege']
od_8 = OrderedDict.fromkeys(list_6, 'True')
print(od_8)
# OrderedDict([('hoge', 'True'), ('fuga', 'True'), ('pege', 'True')])
全部の要素に対して一括で初期の値を設定できるので便利です。ただしfromkeysの性質上ミュータブルな値(リストとか)を初期値に入れる時には注意が必要です。
以上がOrderedDictオブジェクトを作成する方法です。
OrderedDictの要素の追加方法
続いてはOrderedDictオブジェクトに要素を追加する方法を紹介します。
OrderedDictオブジェクトは辞書型のサブクラスなので辞書型と同じように要素を追加することができます。
要素の追加の際は以下のように書きます。
from collections import OrderedDict
od = OrderedDict()
print(od)
# OrderedDict()
od['hoge'] = 10
od['fuga'] = 100
od['pege'] = 0
print(od)
# OrderedDict([('hoge', 10), ('fuga', 100), ('pege', 0)])
辞書型と同じようにキーを指定して要素を追加していきます。
OrderedDictオブジェクト内の要素は追加された順番を保持するので、実装する際は追加する順番を意識しないといけないことに注意が必要です。
OrderedDictの要素の削除方法
続いてはOrderedDictオブジェクトの要素を削除する方法を紹介します。
削除の際はpopitem()を使います。
popitem()を使った削除の際は下記のように書きます。
from collections import OrderedDict
od = OrderedDict()
od['hoge'] = 10
od['fuga'] = 100
od['pege'] = 0
print(od)
# OrderedDict([('hoge', 10), ('fuga', 100), ('pege', 0)])
val = od.popitem()
print(val)
print(od)
# ('pege', 0)
# OrderedDict([('hoge', 10), ('fuga', 100)])
od['pege'] = 99
print(od)
# OrderedDict([('hoge', 10), ('fuga', 100), ('pege', 99)])
val_2 = od.popitem(last=False)
print(val_2)
print(od)
# ('hoge', 10)
# OrderedDict([('fuga', 100), ('pege', 99)])
popitem()を使えば削除した要素を返した後に対象の要素を削除します。
popitem()はlastという引数を渡すことができます。要素を削除する際に先頭の要素か、最後の要素のどちらを削除するかを指定するための引数です。
デフォルトはlast=Trueで最後の追加した要素を削除します。一方でlast=Falseにすると最初に追加した要素を削除します。
popitem()では要素を指定して削除をすることはできないので、要素を指定して削除する場合は通常の辞書型の要素の削除と同じよう下記のように書きます。
from collections import OrderedDict
od = OrderedDict()
od['hoge'] = 10
od['fuga'] = 100
od['pege'] = 0
print(od)
# OrderedDict([('hoge', 10), ('fuga', 100), ('pege', 0)])
del od['pege']
print(od)
# OrderedDict([('hoge', 10), ('fuga', 100)])
delを使用してキーを指定することで指定した要素の削除が可能です。
OrderedDictの移動方法
OrderedDictは辞書型とは異なり指定した要素を先頭、もしくは最後に移動させることが可能です。
要素を先頭、もしくは最後に移動させる際はmove_to_end()を使用します。
移動の際は下記のように書きます。
from collections import OrderedDict
od = OrderedDict()
od['hoge'] = 10
od['fuga'] = 100
od['pege'] = 0
print(od)
od.move_to_end('hoge')
print(od)
# OrderedDict([('fuga', 100), ('pege', 0), ('hoge', 10)])
od.move_to_end('pege', last=False)
print(od)
# OrderedDict([('pege', 0), ('fuga', 100), ('hoge', 10)])
move_to_end()もpopitem()と同様にlastという引数を渡すことができます。要素を先頭に移動させるのか、最後に移動させるのかを指定するための引数です。
デフォルトはlast=Trueで指定した要素を最後に移動させます。一方でlast=Falseにすると指定した要素を先頭に移動させます。
まとめ
Python3.7以上では通常の辞書型でも順序が保証されるようになったので、OrderedDictの出番は非常に少ないと思います。
ですが現場によっては簡単にPythonのバージョンアップができず、OrderedDictを使う必要がある現場も少なくはないと思います。
そのような現場に入っても困らないようにするためにもOrderedDictの最低限の部分は知っておいても損はないと思います。
コメント