递归地添加新的 k:v 对到嵌套字典
recursively add new k:v pair to nested dictionary
我有一个嵌套字典,其中任何级别我都可能有国家/地区信息。我正在应用一个从名为 to_code()
的库中获取的国家/地区规范化函数,它吐出传递的字符串的 ISO 代码。
这是我的函数:
def update_country(dictionary):
for k, v in dictionary.items():
if 'country' in k:
dictionary[k+"_iso"] = to_code(v, fuzzy=True)
elif isinstance(v, dict):
for result in update_country(dictionary=v):
yield result
elif isinstance(v, list):
for d in v:
if isinstance(d, dict):
for result in update_country(dictionary=d):
yield result
想象一下这个嵌套 JSON
JSON = {"company_code": "123456",
"name": "Astrocom AG",
"officers": [{"name": "Abigail Kaloomp",
"country_of_residence": "bvi"},
{"name": "EXPONET limited",
"address": {"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country": "united kingdom"}}],
"address": {"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country": "italia"}}
当我运行
from pprint import pprint
list(update_country(JSON))
pprint(JSON)
我收到以下错误:
Traceback (most recent call last):
File "/home/gabri/.local/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3417, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-39-4ac13e957742>", line 1, in <module>
list(update_country(JSON))
File "<ipython-input-38-8f467b1cdf1b>", line 7, in update_country
for result in update_country(dictionary=v):
File "<ipython-input-38-8f467b1cdf1b>", line 2, in update_country
for k, v in dictionary.items():
RuntimeError: dictionary changed size during iteration
据我了解 - 事实上,如果我没有尝试插入新密钥,而是通过替换以下两行来更新现有密钥:
dictionary[k+"_iso"] = to_code(v, fuzzy=True)
# becomes
dictionary[k] = to_code(v, fuzzy=True) # overwrite existing value
然后我确实得到一个 JSON 国家/地区键我有一个 ISO 代码。
问题是我两者都需要。使用此逻辑是否可行,或者在迭代期间无法更改字典?
您可以像这样拆分迭代:
- 创建所有新键(字典理解为
{f"{k}_iso": v for k, v in dictionary.items() if "country" in k}
)
- 用第 1 步的结果更新你的字典
- 仅在产生结果的条件下执行 for 循环
您可以使用此示例递归更改字典:
JSON = {"company_code": "123456",
"name": "Astrocom AG",
"officers": [{"name": "Abigail Kaloomp",
"country_of_residence": "bvi"},
{"name": "EXPONET limited",
"address": {"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country": "united kingdom"}}],
"address": {"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country": "italia"}}
def abbr(country_name):
if country_name == 'italia':
return 'IT'
elif country_name == 'united kingdom':
return 'UK'
else:
return '?'
def update_country(d):
if isinstance(d, dict):
rv = {}
for k, v in d.items():
if k == 'country':
rv[k + '_iso'] = abbr(v)
rv[k] = update_country(v)
return rv
elif isinstance(d, list):
rv = [update_country(v) for v in d]
return rv
else:
return d
new_JSON = update_country(JSON)
# pretty print the new dictionary:
import json
print(json.dumps(new_JSON, indent=4))
打印:
{
"company_code": "123456",
"name": "Astrocom AG",
"officers": [
{
"name": "Abigail Kaloomp",
"country_of_residence": "bvi"
},
{
"name": "EXPONET limited",
"address": {
"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country_iso": "UK",
"country": "united kingdom"
}
}
],
"address": {
"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country_iso": "IT",
"country": "italia"
}
}
我有一个嵌套字典,其中任何级别我都可能有国家/地区信息。我正在应用一个从名为 to_code()
的库中获取的国家/地区规范化函数,它吐出传递的字符串的 ISO 代码。
这是我的函数:
def update_country(dictionary):
for k, v in dictionary.items():
if 'country' in k:
dictionary[k+"_iso"] = to_code(v, fuzzy=True)
elif isinstance(v, dict):
for result in update_country(dictionary=v):
yield result
elif isinstance(v, list):
for d in v:
if isinstance(d, dict):
for result in update_country(dictionary=d):
yield result
想象一下这个嵌套 JSON
JSON = {"company_code": "123456",
"name": "Astrocom AG",
"officers": [{"name": "Abigail Kaloomp",
"country_of_residence": "bvi"},
{"name": "EXPONET limited",
"address": {"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country": "united kingdom"}}],
"address": {"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country": "italia"}}
当我运行
from pprint import pprint
list(update_country(JSON))
pprint(JSON)
我收到以下错误:
Traceback (most recent call last):
File "/home/gabri/.local/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3417, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-39-4ac13e957742>", line 1, in <module>
list(update_country(JSON))
File "<ipython-input-38-8f467b1cdf1b>", line 7, in update_country
for result in update_country(dictionary=v):
File "<ipython-input-38-8f467b1cdf1b>", line 2, in update_country
for k, v in dictionary.items():
RuntimeError: dictionary changed size during iteration
据我了解 - 事实上,如果我没有尝试插入新密钥,而是通过替换以下两行来更新现有密钥:
dictionary[k+"_iso"] = to_code(v, fuzzy=True)
# becomes
dictionary[k] = to_code(v, fuzzy=True) # overwrite existing value
然后我确实得到一个 JSON 国家/地区键我有一个 ISO 代码。
问题是我两者都需要。使用此逻辑是否可行,或者在迭代期间无法更改字典?
您可以像这样拆分迭代:
- 创建所有新键(字典理解为
{f"{k}_iso": v for k, v in dictionary.items() if "country" in k}
) - 用第 1 步的结果更新你的字典
- 仅在产生结果的条件下执行 for 循环
您可以使用此示例递归更改字典:
JSON = {"company_code": "123456",
"name": "Astrocom AG",
"officers": [{"name": "Abigail Kaloomp",
"country_of_residence": "bvi"},
{"name": "EXPONET limited",
"address": {"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country": "united kingdom"}}],
"address": {"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country": "italia"}}
def abbr(country_name):
if country_name == 'italia':
return 'IT'
elif country_name == 'united kingdom':
return 'UK'
else:
return '?'
def update_country(d):
if isinstance(d, dict):
rv = {}
for k, v in d.items():
if k == 'country':
rv[k + '_iso'] = abbr(v)
rv[k] = update_country(v)
return rv
elif isinstance(d, list):
rv = [update_country(v) for v in d]
return rv
else:
return d
new_JSON = update_country(JSON)
# pretty print the new dictionary:
import json
print(json.dumps(new_JSON, indent=4))
打印:
{
"company_code": "123456",
"name": "Astrocom AG",
"officers": [
{
"name": "Abigail Kaloomp",
"country_of_residence": "bvi"
},
{
"name": "EXPONET limited",
"address": {
"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country_iso": "UK",
"country": "united kingdom"
}
}
],
"address": {
"address_line_1": "somewhere",
"address_line_2": "somewhere_else",
"country_iso": "IT",
"country": "italia"
}
}