递归替换字典中的字符
Posted
技术标签:
【中文标题】递归替换字典中的字符【英文标题】:Recursively replace characters in a dictionary 【发布时间】:2016-04-09 11:35:44 【问题描述】:我如何将所有点 .
更改为下划线(在字典的键中),给定一个任意嵌套的字典?
我尝试的是编写两个循环,但是我将被限制为 2 级嵌套字典。
这...
"brown.muffins": 5,
"green.pear": 4,
"delicious.apples":
"green.apples": 2
...应该变成:
"brown_muffins": 5,
"green_pear": 4,
"delicious_apples":
"green_apples": 2
有没有优雅的方法?
【问题讨论】:
定义遍历字典键/值的方法,如果键有点,则替换,如果值是另一个字典,则输入递归(调用相同的方法,但现在使用这个字典) 你试过什么?不要用“有两个循环”来“任意嵌套”。 递归之美,宝贝 @PeterWood - 这是任何递归的可能性。如果结构嵌套不是很深,它可能会很好。 @PeterWood 堆栈溢出,宝贝:P 【参考方案1】:你可以写一个递归函数,像这样
from collections.abc import Mapping
def rec_key_replace(obj):
if isinstance(obj, Mapping):
return key.replace('.', '_'): rec_key_replace(val) for key, val in obj.items()
return obj
当您使用问题中显示的字典调用它时,您将获得一个新字典,键中的点替换为_
s
'delicious_apples': 'green_apples': 2, 'green_pear': 4, 'brown_muffins': 5
说明
这里,我们只检查当前对象是否是dict
的实例,如果是,则迭代字典,替换键并递归调用函数。如果它实际上不是字典,则按原样返回。
【讨论】:
为什么不用dict
而不是Mapping
?
@IronFist 当您检查它是否是dict
的实例时,您将其限制为仅dict
及其子类。取而代之的是,您稍微放宽了条件,并允许任何具有很少方法的类使其看起来像字典。您可能想查看mapping 定义。
请原谅这里缺乏知识..:P .. 还有一件事,这只是建议,你不认为用tr-except
块包装它是安全的,以防止达到最大迭代如果这很重要,并在必要时提出例外或任何针对它的控制措施......?
@IronFist 这不是生产就绪代码:D 我不希望任何人按原样使用它。如果他们愿意,他们可以增加递归限制:-)【参考方案2】:
假设.
仅存在于键中并且所有字典的内容都是原始文字,真正便宜的方法是使用str()
或repr()
,进行替换,然后ast.literal_eval()
将其取回:
d =
"brown.muffins": 5,
"green.pear": 4,
"delicious_apples":
"green.apples": 2
# correct brace
结果:
>>> import ast
>>> ast.literal_eval(repr(d).replace('.','_'))
'delicious_apples': 'green_apples': 2, 'green_pear': 4, 'brown_muffins': 5
如果字典在键之外有.
,我们可以使用正则表达式更仔细地替换,以查找'ke.y':
之类的字符串并仅替换那些位:
>>> import re
>>> ast.literal_eval(re.sub(r"'(.*?)':", lambda x: x.group(0).replace('.','_'), repr(d)))
'delicious_apples': 'green_apples': 2, 'green_pear': 4, 'brown_muffins': 5
如果您的字典非常复杂,在值中包含'.'
和类似字典的字符串等,请使用真正的递归方法。不过,就像我一开始所说的那样,这是一种便宜的方式。
【讨论】:
这也将替换值,虽然 @cricket_007 我想他说的是水果和甜点的整数倍。 @erip - 仍然不是 OP 所要求的 假设你没有'my.key': __my_method
:P
@erip 理想情况下,它也应该对未来的访问者有用,而不仅仅是 OP 的特定情况。不过很有创意以上是关于递归替换字典中的字符的主要内容,如果未能解决你的问题,请参考以下文章