search
LoginSignup
1

posted at

[python] Key-Value 形式の dict を階層構造の dict に

やりたいこと

記事タイトルはちょっとわかりづらいというか不正確な気がしますが、やりたいことはコレ。

# ↓これを
src = {
    "aaa": "A",
    "bbb.ccc": "BC",
    "bbb.ddd": "BD",
}

# ↓こうしたい
{
  "aaa": "A",
  "bbb": {
    "ccc": "BC",
    "ddd": "BD"
  }
}

コードスニペット

とりあえず下記の function で実現できた。
もっとキレイに書けそうな気がするし、探せばライブラリもありそうだけど。

def kv_to_stare(kv, path_delimiter=".", base_path=""):
    result = {}
    for k, v in kv.items():
        if len(base_path) > 0 and not k.startswith(f"{base_path}{path_delimiter}"):
            continue
        base_path_len = len(base_path)
        path = k[base_path_len:].strip(path_delimiter)
        paths = path.split(path_delimiter)
        current_path = paths[0]
        if len(paths) == 1:
            result[current_path] = v
        else:
            next_base_path = f"{base_path}.{current_path}".strip(path_delimiter)
            result[current_path] = kv_to_stare(kv, path_delimiter, next_base_path)
    return result

使用例

import json

# Inputデータ
src = {
    "aaaa": "AAA",
    "bbbb": "BBB",
    "cccc.dddd": "CCCDDD",
    "cccc.eeee": "CCCEEE",
    "ffff.gggg.gggg": "FGG",
    "ffff.gggg.hhhh": "FGH",
    "ffff.iii.aaa": "FIA",
    "cccc.kkkk": "CCCKKK",
}

# 実行&表示
result = kv_to_stare(src)
print(json.dumps(result, indent=2))

### ▼結果 ###
{
  "aaaa": "AAA",
  "bbbb": "BBB",
  "cccc": {
    "dddd": "CCCDDD",
    "eeee": "CCCEEE",
    "kkkk": "CCCKKK"
  },
  "ffff": {
    "gggg": {
      "gggg": "FGG",
      "hhhh": "FGH"
    },
    "iii": {
      "aaa": "FIA"
    }
  }
}

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
What you can do with signing up
1