【Python】JSONから指定のエントリを抽出＆他のエントリ内のプロパティと一致する場合はそのエントリ内の値も取得する方法

# 概要
JSONファイルから指定のエントリを抽出し、かつ、他のエントリ内の指定のプロパティと一致する場合はそのエントリ内の値も一緒に取得する方法を、備忘録も兼ねて記載します。
（文章だと意図が伝わりづらいので、サンプルコードを...）

# サンプルコード解説
以下のようなJSONがあるとします。
サンプルなのでわかりやすいようにしていますが、実際は支店（`branch`)も製品（`product_code`)もたくさんある前提です。

```001_sample_response.json
{
    "response": {
        "status": "0000",
        "company_code": "12345",
        "branch": {
            "tokyo": [
                {
                    "product_code": "001",
                    "unit_price": "100",
                    "quantity": "10",
                    "sales_amount": "1000",
                    "tokyo_status": "Tokyo、達成です！"
                },
                {
                    "product_code": "002",
                    "unit_price": "200",
                    "quantity": "1",
                    "sales_amount": "200",
                    "tokyo_status": "Tokyo、未達です！"
                }
            ],
            "osaka": [
                {
                    "product_code": "001",
                    "unit_price": "100",
                    "quantity": "2",
                    "sales_amount": "200",
                    "osaka_status": "Osaka、未達です！"
                },
                {
                    "product_code": "002",
                    "unit_price": "200",
                    "quantity": "5",
                    "sales_amount": "1000",
                    "osaka_status": "Osaka、達成です！"
                }
            ]
        }
    }
}
```

上記から、大阪支店の情報（`osaka`エントリ全体）を抽出し、かつ、プロパティの`product_code`と`unit_price`の両方が一致する東京支社のステータスを取り出すコードを紹介します。今回は`001`から`100`まである想定なので`range`でループを作成しています。

```py
import os
import json

# 出力ディレクトリを作成
output_dir = "./sample_osaka_files"
if not os.path.exists(output_dir):
    os.makedirs(output_dir)

for i in range(1, 100):
    json_file_path = f"./sample_json_files/{str(i).zfill(3)}_sample_response.json"
    output_file_path = f"{output_dir}/{str(i).zfill(3)}_osaka.json"

    try:
        with open(json_file_path, "r", encoding="utf-8") as json_file:
            data = json.load(json_file)

        if "response" in data and "branch" in data["response"]:
            branch = data["response"]["branch"]
            if "tokyo" in branch and "osaka" in branch:
                tokyo_branch = branch["tokyo"]
                osaka_branch = branch["osaka"]
                entries_with_status = []
                for osaka in osaka_branch:
                    osaka_factors = (
                        osaka.get("product_code"),
                        osaka.get("unit_price")
                    )
                    for tokyo in tokyo_branch:
                        tokyo_factors = (
                            tokyo.get("product_code"),
                            tokyo.get("unit_price")
                        )
                        if osaka_factors == tokyo_factors:
                            osaka["tokyo_status"] = tokyo.get("tokyo_status")
                            entries_with_status.append(osaka)
                            break

                if entries_with_status:
                    entries_with_status.insert(0, {"branch": "osaka"})
                    with open(output_file_path, "w", encoding="utf-8") as output_file:
                        json.dump(entries_with_status, output_file, ensure_ascii=False, indent=4)

    except (FileNotFoundError, json.JSONDecodeError) as e:
        print(f"処理エラー: {json_file_path} - {e}")
```

実行結果は以下になります。
例えば`product_code`が`001`＆`unit_price`が`100`の製品の場合、大阪支店の情報（`quantity`や`sales_amount`）を抽出しつつ、同じく`product_code`が`001`＆`unit_price`が`100`である東京支店のステータスも取得できます。

```001_osaka.json
[
    {
        "branch": "osaka"
    },
    {
        "product_code": "001",
        "unit_price": "100",
        "quantity": "2",
        "sales_amount": "200",
        "osaka_status": "Osaka、未達です！",
        "tokyo_status": "Tokyo、達成です！"
    },
    {
        "product_code": "002",
        "unit_price": "200",
        "quantity": "5",
        "sales_amount": "1000",
        "osaka_status": "Osaka、達成です！",
        "tokyo_status": "Tokyo、未達です！"
    }
]
```

ネストがかなり深く力技のコーディングですが、これで作業すると100件とか整理する必要がある場合は非常に楽でした。