問題点
JSONのような階層構造の辞書型でデータを扱うケースはよくあると思います。
階層が深くなり指定のデータにたどり着くために、以下のコードのように階層によって爆増するコードを書いてませんか?
if 'key1' in target_dict:
target_dict_key1 = target_dict['key1']
if 'key2' in target_dict_key1 :
target_dict_key2 = target_dict_key1['key2']
...
else:
target_dict_key1.setdefault('key2',dict())
....
やりたいこと
- 階層化された辞書型から指定の階層の辞書型を取得したい。
- また、もし階層途中がなければ、指定階層まで辞書を作成し、最終層の辞書型を取得したい。
データは以下のようになっていたとします。
data_dict = {
'tokyo':{
'shinjuku':{
'zaiko':{
'A':3,
'B':4,
'C':5,
},
},
'shibuya':{
'zaiko':{
'A':5,
'B':8,
},
},
}
}
tokyoのsinjukuの在庫データを取得したい。
データ階層のキーワードがあるかどうかの確認もしつつ探し出さなければなりません。
さらに、新しく'D'という在庫を追加したい。とか、'yoyaku'という新しい管理データを挿入したいというとき、冒頭のようなコードを記述していると大変なことになります。
解決
以下のような、二つの関数をネストさせれば、コードの膨張を防ぐことができます。
def _serach_dict_(target_dict,dict_layer):
result_dict = None
if isinstance(dict_layer,list):
if dict_layer:
key = dict_layer[0]
if key in target_dict:
if not isinstance(target_dict[key],dict):
target_dict[key] = dict()
target_dict = target_dict[key]
dict_layer = dict_layer[1:]
if dict_layer:
result_dict = _serach_dict_(target_dict,dict_layer)
else:
return target_dict
else:
result_dict = _create_dict_(target_dict,dict_layer)
return result_dict
def _create_dict_(target_dict,dict_layer):
result_dict = None
if isinstance(dict_layer,list) and isinstance(target_dict,dict):
if dict_layer:
key = dict_layer[0]
target_dict.setdefault(key, dict())
result_dict = target_dict[key]
dict_layer = dict_layer[1:]
if dict_layer:
result_dict = _create_dict_(result_dict,dict_layer)
else:
return result_dict
return result_dict
_serach_dict_関数内で、_create_dict_を使用します。
_serach_dict_関数の引数
target_dict:辞書型データ
dict_layer:探し出す階層構造リスト
dict_layeの例は以下の通り。
dict_layer = ['tokyo','shinjuku','zaiko']
使用方法
tokyoのsinjukuの在庫データを取得
dict_layer = ['tokyo','shinjuku','zaiko']
import json
result_dict = _serach_dict_(data_dict,dict_layer)
print(json.dumps(data_dict,indent=2))
result_dict.setdefault('D', 30)
print(json.dumps(data_dict,indent=2))
結果
{
"tokyo": {
"shinjuku": {
"zaiko": {
"A": 3,
"B": 4,
"C": 5
}
},
"shibuya": {
"zaiko": {
"A": 5,
"B": 8
}
}
}
}
{
"tokyo": {
"shinjuku": {
"zaiko": {
"A": 3,
"B": 4,
"C": 5,
"D": 30
}
},
"shibuya": {
"zaiko": {
"A": 5,
"B": 8
}
}
}
}
shinjukuにyoyakuデータを作り、Aを15個登録します。
dict_layer = ['tokyo','shinjuku','yoyaku']
import json
result_dict = _serach_dict_(data_dict,dict_layer)
print(json.dumps(data_dict,indent=2))
result_dict.setdefault('A', 15)
print(json.dumps(data_dict,indent=2))
結果
{
"tokyo": {
"shinjuku": {
"zaiko": {
"A": 3,
"B": 4,
"C": 5
},
"yoyaku": {}
},
"shibuya": {
"zaiko": {
"A": 5,
"B": 8
}
}
}
}
{
"tokyo": {
"shinjuku": {
"zaiko": {
"A": 3,
"B": 4,
"C": 5
},
"yoyaku": {
"A": 15
}
},
"shibuya": {
"zaiko": {
"A": 5,
"B": 8
}
}
}
}
注意点
このコードではdict_layer で指定したキーワードをdict型に置き換えてしまいます。
list型の混在やそのほかデータ型を保護するためには、_serach_dict_関数に多少手を入れる必要があります。