如何重命名字典列表中深度嵌套的键(Python 3)?

Posted

技术标签:

【中文标题】如何重命名字典列表中深度嵌套的键(Python 3)?【英文标题】:How to rename a deeply nested key in list of dictionaries (Python 3)? 【发布时间】:2021-08-03 20:56:56 【问题描述】:

给定以下字典(很长的字典列表的一部分):

'diet': 'Diet 0': 'gender': 0,
   'nutrients': 'Alcohol': 'min': 0, 'max': 14, 'unit': 'oz',
    'Caffeine': 'min': 0, 'max': 400, 'unit': 'mg',
    'Copper': 'min': 0, 'max': 0, 'unit': 'mg',
    'Calcium': 'min': 1000, 'max': 2500, 'unit': 'mg',
    'Choline': 'min': 425, 'max': 3500, 'unit': 'mg',
    'Cholesterol': 'min': 0, 'max': 300, 'unit': 'mg',
    'Fluoride': 'min': 0, 'max': 0, 'unit': 'mg',
    'SaturatedFat': 'min': 0, 'max': -1, 'unit': 'g',
    'VitaminA': 'min': 2330, 'max': 10000, 'unit': 'IU',
    'VitaminC': 'min': 75, 'max': 2000, 'unit': 'mg',
    'VitaminD': 'min': 15, 'max': 100, 'unit': 'mcg',
    'VitaminE': 'min': 15, 'max': 1000, 'unit': 'mg',
    'VitaminK': 'min': 0, 'max': 0, 'unit': 'mcg',
    'VitaminB1': 'min': 1.1, 'max': 0, 'unit': 'mg',
    'VitaminB2': 'min': 0, 'max': 0, 'unit': 'mg',
    'VitaminB5': 'min': 0, 'max': 0, 'unit': 'mg',
    'VitaminB3': 'min': 0, 'max': 0, 'unit': 'mg',
    'VitaminB6': 'min': 0, 'max': 0, 'unit': 'mg',
    'VitaminB12': 'min': 2.4, 'max': 999999999, 'unit': 'mcg',
    'Fiber': 'min': 21, 'max': 70, 'unit': 'g',
    'Folate': 'min': 400, 'max': 1000, 'unit': 'mcg',
    'FolicAcid': 'min': 0, 'max': 0, 'unit': 'mcg',
    'Iodine': 'min': 0, 'max': 0, 'unit': 'mcg',
    'Iron': 'min': 18.0, 'max': 45, 'unit': 'mg',
    'Magnesium': 'min': 310, 'max': 350, 'unit': 'mg',
    'Manganese': 'min': nan, 'max': 0, 'unit': 'mg',
    'Phosphorus': 'min': 700, 'max': 4000, 'unit': 'mg',
    'Potassium': 'min': 2600, 'max': 0, 'unit': 'mg',
    'Selenium': 'min': 0, 'max': 0, 'unit': 'mcg',
    'Sodium': 'min': 500, 'max': 2300, 'unit': 'mg',
    'Sugar': 'min': nan, 'max': 24, 'unit': 'g',
    'Zinc': 'min': 8.0, 'max': 40, 'unit': 'mg'

我的列表中有 10000 个这样的字典,我想将 SaturatedFat 键更改为 Saturated Fat。 试过ast:

import ast
ast.literal_eval(str(diet_specs_dicts[0]).replace("'SaturatedFat':","'Saturated Fat':"))

返回错误:

----------------------------------- ---------------------------- ValueError Traceback(最近一次调用 最后)在 1 导入 ast ----> 2 ast.literal_eval(str(diet_specs_dicts[0]).replace("'SaturatedFat':","'Saturated 胖子':"))

/usr/lib/python3.8/ast.py in literal_eval(node_or_string) 97 左右返回 98 返回_convert_signed_num(节点) ---> 99 返回 _convert(node_or_string) 100 101

/usr/lib/python3.8/ast.py 在 _convert(node) 86 如果 len(node.keys) != len(node.values): 87 _raise_malformed_node(节点) ---> 88 返回 dict(zip(map(_convert, node.keys), 89 地图(_convert,node.values))) 90 elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):

/usr/lib/python3.8/ast.py 在 _convert(node) 86 如果 len(node.keys) != len(node.values): 87 _raise_malformed_node(节点) ---> 88 返回 dict(zip(map(_convert, node.keys), 89 地图(_convert,node.values))) 90 elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):

/usr/lib/python3.8/ast.py 在 _convert(node) 86 如果 len(node.keys) != len(node.values): 87 _raise_malformed_node(节点) ---> 88 返回 dict(zip(map(_convert, node.keys), 89 地图(_convert,node.values))) 90 elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):

/usr/lib/python3.8/ast.py 在 _convert(node) 86 如果 len(node.keys) != len(node.values): 87 _raise_malformed_node(节点) ---> 88 返回 dict(zip(map(_convert, node.keys), 89 地图(_convert,node.values))) 90 elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):

/usr/lib/python3.8/ast.py 在 _convert(node) 86 如果 len(node.keys) != len(node.values): 87 _raise_malformed_node(节点) ---> 88 返回 dict(zip(map(_convert, node.keys), 89 地图(_convert,node.values))) 90 elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):

/usr/lib/python3.8/ast.py 在 _convert(node) 96 其他: 97 左右返回 ---> 98 返回 _convert_signed_num(node) 99 返回 _convert(node_or_string) 100

/usr/lib/python3.8/ast.py in _convert_signed_num(node) 其他 73 条: 74 返回 - 操作数 ---> 75 返回 _convert_num(node) 76 def _convert(节点): 77 if isinstance(node, Constant):

/usr/lib/python3.8/ast.py in _convert_num(node) 64 def_convert_num(节点): 65 if not isinstance(node, Constant) or type(node.value) not in (int, float, complex): ---> 66 _raise_malformed_node(节点) 67 返回节点值 68 def_convert_signed_num(节点):

/usr/lib/python3.8/ast.py 在 _raise_malformed_node(node) 61 node_or_string = node_or_string.body 62 def _raise_malformed_node(节点): ---> 63 raise ValueError(f'malformed node or string: node!r') 64 def_convert_num(节点): 65 if not isinstance(node, Constant) or type(node.value) not in (int, float, complex):

ValueError:错误的节点或字符串:<_ast.name object at>

【问题讨论】:

使用 json 可能会更好。您可以 json.dumps 将字典转换为字符串,然后进行 str 替换,然后 json.loads 将其恢复为字典 你有没有尝试将'SaturatedFat'的值复制到'Saturated Fat',然后用my_dict.pop('key', None)删除原来的key? 你有一个变量“nan”,值是多少? @Yuri nan 已修复。它应该是 0。 @AimiHat 是的,没用。这是一个嵌套的字典。 【参考方案1】:

给你

lst = ['diet': 'Diet 0': 'gender': 0,
   'nutrients': 'Alcohol': 'min': 0, 'max': 14, 'unit': 'oz',
    'Caffeine': 'min': 0, 'max': 400, 'unit': 'mg',
    'Copper': 'min': 0, 'max': 0, 'unit': 'mg',
    'Calcium': 'min': 1000, 'max': 2500, 'unit': 'mg',
    'Choline': 'min': 425, 'max': 3500, 'unit': 'mg',
    'Cholesterol': 'min': 0, 'max': 300, 'unit': 'mg',
    'Fluoride': 'min': 0, 'max': 0, 'unit': 'mg',
    'SaturatedFat': 'min': 0, 'max': -1, 'unit': 'g',
    'VitaminA': 'min': 2330, 'max': 10000, 'unit': 'IU',
    'VitaminC': 'min': 75, 'max': 2000, 'unit': 'mg',
    'VitaminD': 'min': 15, 'max': 100, 'unit': 'mcg',
    'VitaminE': 'min': 15, 'max': 1000, 'unit': 'mg',
    'VitaminK': 'min': 0, 'max': 0, 'unit': 'mcg',
    'VitaminB1': 'min': 1.1, 'max': 0, 'unit': 'mg',
    'VitaminB2': 'min': 0, 'max': 0, 'unit': 'mg',
    'VitaminB5': 'min': 0, 'max': 0, 'unit': 'mg',
    'VitaminB3': 'min': 0, 'max': 0, 'unit': 'mg', ............................]

for d in lst:
    d['Saturated Fat'] = d.pop('SaturatedFat')
print(lst)

【讨论】:

很抱歉,它不起作用。它说没有这样的密钥:--------------------------------------------------------------------------- KeyError Traceback (most recent call last) &lt;ipython-input-16-80d329dbdb21&gt; in &lt;module&gt; ----&gt; 1 diet_specs_dicts[0].pop('SaturatedFat') KeyError: 'SaturatedFat' 你能发布完整的错误吗?我不确定你为什么提到diet_specs_dicts[0] ...你是否缩进只替换“0”索引?? 在我的情况下,它是列表的名称,所以我采用第一个 (0) 元素并尝试更改键名。在您的情况下,列表的名称是 lst。 发布完整的错误,将给出解决方案。代码有效,可能需要小修改。 在这里,我将使用列表中的前 2 个字典:lst = [diet_specs_dicts[0], diet_specs_dicts[1]] 并运行您的解决方案:for d in lst: d['Saturated Fat'] = d.pop('SaturatedFat')【参考方案2】:

您可以使用递归函数来更改键,无论它出现在嵌套层次结构中的什么地方:

针对函数定义中的拼写错误进行了编辑

>>> d = 'diet': 'Diet 0': 'gender': 0,
...:    'nutrients': 'Alcohol': 'min': 0, 'max': 14, 'unit': 'oz',
...:     'Caffeine': 'min': 0, 'max': 400, 'unit': 'mg',
...:     'SaturatedFat': 'min': 0, 'max': -1, 'unit': 'g',
...:     'VitaminA': 'min': 2330, 'max': 10000, 'unit': 'IU'

>>> def replace_key(d, old_key, new_key):
...:     for k, v in tuple(d.items()):
...:          if k == old_key:
...:              d[new_key] = d.pop(old_key)
...: 
...:          if isinstance(v, dict):
...:              replace_key(v, old_key, new_key)
...: 

>>> replace_key(d, old_key='SaturatedFat', new_key='Saturated Fat')
>>> d
'diet': 'Diet 0': 'gender': 0,
   'nutrients': 'Alcohol': 'min': 0, 'max': 14, 'unit': 'oz',
    'Caffeine': 'min': 0, 'max': 400, 'unit': 'mg',
    'VitaminA': 'min': 2330, 'max': 10000, 'unit': 'IU',
    'Saturated Fat': 'min': 0, 'max': -1, 'unit': 'g'

这个函数就地改变字典,并返回None,但很容易修改为返回副本,保持原字典不变:

>>> import copy
>>> def replace_key(d, old_key, new_key):
...:     d = copy.deepcopy(d)
...:     for k, v in tuple(d.items()):
...:          if k == old_key:
...:              d[new_key] = d.pop(old_key)
...: 
...:          if isinstance(v, dict):
...:              replace_key(v, old_key, new_key)
...: 
...:     return d

【讨论】:

这里的 x 是什么:x(v, old_key, new_key) 对不起 - “x”是一个错字。应该是“replace_key”。我已经更新了答案

以上是关于如何重命名字典列表中深度嵌套的键(Python 3)?的主要内容,如果未能解决你的问题,请参考以下文章

递归地重命名字典列表中的字典键

Python:从父子值列表创建嵌套字典

Python ❀ 字典

Python ❀ 字典

在嵌套字典和列表中查找所有出现的键

如何将带有嵌套字典的列表写入 csv 文件?