ネストした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、日本語情報が全くさっぱりびっくりするほど出てこないな。
便利なのでみんなも使うといいと思います。