35
25

More than 3 years have passed since last update.

Pythonでネストしたdictをマージしたい

Posted at

ネストしたdictをマージしたかったのだけど、適切な記事が全く見当たらない。

とりあえずdictをつくる。

dict1 = {
    "depth1_a": "x1a",
    "depth1_b": "x1b",
    "depth2_1": {
        "depth2_a" : "x2a",
        "depth2_b" : "x2b"
    },
    "depth3_1": {
        "depth3_2": {
            "depth3_3_a" : "x33a",
            "depth3_3_b" : "x33b"
        }
    }
}

dict2 = {
    "depth1_a": "y1a",
    "depth1_c": "y1c",
    "depth2_1": {
        "depth2_a" : "y2a",
        "depth2_c" : "y2c"
    },
    "depth3_1": {
        "depth3_2": {
            "depth3_3_a" : "y33a",
            "depth3_3_c" : "y33c"
        }
    }
}

結果として欲しいのは、"depthx_a"はdict2の値で上書きされる、"depthx_b"と"depthx_c"は両方とも残る、というものです。

複数の辞書のマージ方法いろいろなどを参考に幾つか試してみたのですが、ネストの二段階目以降で"depthx_b"が消えます。

dict1.update(dict2)
print(dict1)

{
    "depth1_a": "y1a",
    "depth1_b": "x1b",
    "depth2_1": {
        "depth2_a": "y2a",
        "depth2_c": "y2c"
    },
    "depth3_1": {
        "depth3_2": {
            "depth3_3_a": "y33a",
            "depth3_3_c": "y33c"
        }
    },
    "depth1_c": "y1c"
}

ネストの一段階目にあるdepth1_a/depth1_b/depth1_cは想定通りになりましたが、それ以外は中身を見に行かずにキーで上書きされてしまいました。

Python3.3からはChainMapというのがあるらしいので試してみます。

from collections import ChainMap
dict_map = ChainMap(dict1, dict2)
dict(dict_map)

{
    "depth1_a": "y1a",
    "depth1_c": "y1c",
    "depth2_1": {
        "depth2_a": "y2a",
        "depth2_c": "y2c"
    },
    "depth3_1": {
        "depth3_2": {
            "depth3_3_a": "y33a",
            "depth3_3_c": "y33c"
        }
    },
    "depth1_b": "x1b"
}

はいだめー。

結局最終的に自力でやるしかないのかよ、めんどくさいなあ、などと彷徨ってたらdictknife.deepmergeとかいうのを見つけました。
名前からして期待しかない。

from dictknife import deepmerge
deepmerge(dict1, dict2)

{
    "depth1_a": "y1a",
    "depth1_b": "x1b",
    "depth2_1": {
        "depth2_a": "y2a",
        "depth2_b": "x2b",
        "depth2_c": "y2c"
    },
    "depth3_1": {
        "depth3_2": {
            "depth3_3_a": "y33a",
            "depth3_3_b": "x33b",
            "depth3_3_c": "y33c"
        }
    },
    "depth1_c": "y1c"
}

これだよ俺の求めていたものは!

ただ残念ながら異なる型を突っ込んだ時の挙動が微妙です。
"depth3_3_a": Noneみたいにリテラル値にNoneを突っ込んだら上書きされてNoneになるのですが、ネストの枝そのものを削除したくて"depth3_2": Noneとしたら単に無視されました。
それならばと"depth3_2": ""にしたらエラーになりました。
残念。

しかしこのdeepmerge、日本語情報が全くさっぱりびっくりするほど出てこないな。
便利なのでみんなも使うといいと思います。

35
25
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
35
25