1. はじめに
この問題集は、Pythonの基礎を習得した後、次の段階へ進みたい人のサポートをすることが目的です。
また、競技プログラミングとは異なり、複雑なアルゴリズムの問題ではなく「可読性の最大化」に焦点を当てた問題が中心となります。
2. 問題
"""
No.8 ネストされた辞書
次のように、keyが'.'区切りの文字列である辞書dictionaryが与えられます。
keyを'.'で分割し、ネストされた辞書を作成してください。
"""
from typing import Any
# 与えられる辞書の例(あくまで一例です)
dictionary: dict[str, Any] = {
'food.fruit.apple': {'price': 150},
'food.fruit': {'place': '1F'},
}
# 期待される結果
expected = {
'food': {
'fruit': {
'apple': {'price': 150},
'place': '1F',
},
},
}
3. 解答例
from dictknife import deepmerge
from nesteddict import NestedDict
nested = {}
for key, value in dictionary.items():
nested = deepmerge(nested, NestedDict({key: value}))
from dictknife import deepmerge
from nesteddict import NestedDict
nested = deepmerge(*[NestedDict({key: value}) for key, value in dictionary.items()])
4. 採点基準
- 「怠惰」になれましたか?
5. 解説
まさか、自力実装してしまいましたか?
という冗談は置いといて、今回は知っていると便利なライブラリ2選の紹介です。
初めにnesteddictライブラリですが、これはkeyが "." 区切りの辞書をネストされた辞書に変換してくれます。
from nesteddict import NestedDict
dictionary = {
'food.fruit.apple': {'price': 150},
}
nested = NestedDict(dictionary)
print(nested)
{'food': {'fruit': {'apple': {'price': 150}}}}
これだけで良いのでは?と思うかもしれませんが、実は落とし穴があります。
実際、例に挙げた辞書を変換すると期待通りになりません。
from nesteddict import NestedDict
dictionary = {
'food.fruit.apple': {'price': 150},
'food.fruit': {'place': '1F'},
}
nested = NestedDict(dictionary)
print(nested)
{'food': {'fruit': {'place': '1F'}}}
'apple'以下のデータが消えてしまっていますね。
何が起きているのかというと、次の2つの辞書がマージされるときに2階層目以降のデータが上書きされてしまうのです。
key_1 = 'food.fruit.apple'
dictionary_1 = NestedDict({key_1: dictionary[key_1]})
print(f'{dictionary_1=}')
key_2 = 'food.fruit'
dictionary_2 = NestedDict({key_2: dictionary[key_2]})
print(f'{dictionary_2=}')
merged = dictionary_1 | dictionary_2
print(f'{merged=}')
dictionary_1={'food': {'fruit': {'apple': {'price': 150}}}}
dictionary_2={'food': {'fruit': {'place': '1F'}}}
merged={'food': {'fruit': {'place': '1F'}}}
これを適切にマージするために、dictknifeライブラリのdeepmerge関数を使用します。
Pythonでネストしたdictをマージしたい - Qiita
dictknife,jsonknifeの機能を整理 - hatenablog.com
deep_merged = deepmerge(dictionary_1, dictionary_2)
print(f'{deep_merged=}')
deep_merged={'food': {'fruit': {'apple': {'price': 150}, 'place': '1F'}}}
期待通りにマージされていますね。
これを繰り返すことで、目的のネストされた辞書が得られます。
どちらも有名なライブラリではないですが、知っていると時折活躍してくれます。
例えばiniファイルを読み込むとき、セクション名が "." 区切りだとこの問題と同じ状況になります。
Pythonでiniファイルを読み込むライブラリ「configparser」 - Qiita
6. テストコード
from dictknife import deepmerge
from nesteddict import NestedDict
nested = {}
for key, value in dictionary.items():
nested = deepmerge(nested, NestedDict({key: value}))
print(nested)
assert nested == expected
{'food': {'fruit': {'apple': {'price': 150}, 'place': '1F'}}}