0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Python 階層化されたDictから指定の階層を探し、なければ作成する

Posted at

問題点

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_関数に多少手を入れる必要があります。

0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?