5
6

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 1 year has passed since last update.

【Python】ネストされた辞書型配列の要素を再帰的に取得する方法

Last updated at Posted at 2021-12-05

###はじめに
pythonでは、JSON形式のデータをdict型(辞書型配列)に変換して扱うケースは多いと思います。その際、JSONの階層が可変であったり、list型を含んでいたりするなどの複雑な構造を持つデータに対して、特定のKeyを指定して値を検索・取得できる関数があると便利だなと考え、勉強の一環で作ってみました。

※既にあるのかも知れませんが、ググっても出てこなかったのであくまで教材・課題のつもりで...
※ご指摘、ご指南いただけるとありがたいです

###環境
macOS Monterey 12.0.1
Python 3.9.2
Visual Studio Code

###コード
関数内部で関数自身を呼び(再帰関数)、ネストが可変でも対応できるように実装。list型が含まれる場合にも対応しています。

util.py
def dict_search(d,key):
    
    if not d or not key:
        return None
    elif isinstance(d, dict):
        if key in d:
            return d.get(key)
        else:
            l = [dict_search(d.get(dkey),key) for dkey in d if isinstance(d.get(dkey),dict) or isinstance(d.get(dkey),list)]
            return [lv for lv in l if not lv is None].pop(0) if any(l) else None
    elif isinstance(d,list):
        li = [dict_search(e,key) for e in d if isinstance(e,dict) or isinstance(e,list)]
        return [liv for liv in li if not liv is None].pop(0) if any(li) else None
    else:
        return None

###動作検証
実際にネスト深めのJSONファイル(sumple.json)を用意して検証してみます。同じ階層のディレクトリに以下のファイルがある環境とします。
・sumple.json
・util.py
・test.py

sumple.json
{
    "data": {
        "orders": {
            "edges": [
                {
                    "node": {
                        "id": "4595490455781",
                        "nodeName": "#123456",
                        "customer": {
                            "id": "abcdefg@hijklmn.com",
                            "name": "kajuta"
                        }
                    }
                }
            ]
        }
    }
}

#####:使用例:
別ファイル(util.py)に関数を定義したので、from ~ importを使って関数をインポートして使用してみます。jsonファイルの読み込みについての説明は割愛します。

test.py
from util import dict_search
import json

# jsonを読み込んでdictに変換
with open('sumple.json','r') as f:
    j_dict = json.load(f)

# keyを指定してdict内の要素を取得(この例では'name'の値を取得)
result = dict_search(j_dict,'name')

# 出力
print(result)

実行結果は以下のとおり。途中でlistを含む階層の奥にある"name"の値を取得できているのがわかります。

console
kajuta

#####:検証:
「name」というkeyが別階層に重複して存在するサンプルで検証

sumple2.json
{
    "node": {
        "id": "4595490455781",
        "name": "#123456",
        "customer": {
            "id": "abcdefg@hijklmn.com",
            "name": "kajuta"
        }
    }
}

実行結果は予想通り、浅い階層から先にヒットしました。

console
#123456

このようにkeyが重複して存在する場合に、何番目の要素にヒットさせるかを、引数で指定できるようにしても面白いかもしれません。

###おわりに
最近、API連携などの開発を行なっていて、その際に得られたJSON形式のデータから特定の値を取得する方法をいろいろ模索していました。大抵は与えられるJSONの階層やKeyが事前にわかっている場合が多いとは思いますが、階層が複雑な場合や可変の場合のベストな方法はないかと思い、勉強のつもりで自分なりに考えてみたので投稿しました。

ご指摘・ご指南等あれば、是非ともよろしくお願いします。

###参考
Pythonで再帰関数を作る方法【初心者向け】
Pythonで理解する再帰関数
Pythonのリストの深さを再帰的に計算する:空のリストの扱いに注意しよう

5
6
2

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
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?