用映射字典的值替换嵌套字典中的占位符

Posted

技术标签:

【中文标题】用映射字典的值替换嵌套字典中的占位符【英文标题】:Replace placeholder in nested dict with values of mapping dict 【发布时间】:2017-01-13 02:10:54 【问题描述】:

我有一个嵌套字典,它可以在键和值中包含占位符。

example_dict = 'dict1': '%(map3)s': 'data': 'tmp',
                                 '%(map2)s': 'freshdata': 'testtest',
             'dict2': '%(map3)s': 'data': '%(map1)s', '%(map3)s': 'status': 'available'

我有一个映射字典,带有占位符映射:

mapping_dict= 
    "map1": [1,2,2],
    "map2": "qwerz",
    "map3": "asdfasdf"

如果占位符位于 VALUE 位置,mapping_dict 的相应映射也可能包含另一个数据类型而不是字符串作为值,例如列表或整数。如何将此数据类型传递给原始字典?我不知道如何制作占位符,例如列表。

信息:mapping_dict 包含的键可能比给定的example_dict 包含的键多。

我想要一个函数,用 mapping_dict 的值替换给定字典的占位符。

什么是一个好的递归实现?

【问题讨论】:

这是一个简单的 (a) iterate-on-base-type, (b) inspect-item-type, (c) goto a;直到你得到一个字符串或不可迭代的类型......你有什么问题? 列表不能是字典键。除非您要使用列表的字符串表示形式。 【参考方案1】:

使用堆栈来导航键值对,您可以弹出键来重命名它们,对于值,做同样的事情,除了尝试看看您是否可以使用ast.literal_eval 将它们评估为 Python 文字来处理您的列表情况.

import ast
from copy import deepcopy

example_dict = 
    'dict1': 
        '%(map3)s': 'data': 'tmp',
        '%(map2)s': 'freshdata': 'testtest'
    ,
    'dict2': 
        '%(map3)s': 'data': '%(map1)s'
    


mapping_dict= 
    "map1": [1,2,2],
    "map2": "qwerz",
    "map3": "asdfasdf"


def sub_placeholders(orig, subs):
    d = deepcopy(orig)
    todo = [d]
    while todo:
        nxt = todo.pop()
        for k, v in nxt.items():
            nxt[k % mapping_dict] = nxt.pop(k)
            if isinstance(v, dict):
                todo.append(v)
            elif isinstance(v, str):
                nxt[k] = v % subs
                try:
                    nxt[k] = ast.literal_eval(nxt[k])
                except ValueError:
                    pass
    return d

运行sub_placeholders(example_dict, example_mapping)会给你:

'dict1': 'asdfasdf': 'data': 'tmp', 'qwerz': 'freshdata': 'testtest',
 'dict2': 'asdfasdf': 'data': [1, 2, 2]

【讨论】:

【参考方案2】:

这是一个递归选项,删除现有键并添加新键,它们应用“格式”和“命名”占位符。注意:在这种情况下,我们正在修改输入字典:

from pprint import pprint

example_dict = 'dict1': '%(map1)s': 'data': 'tmp', '%(map2)s': 'freshdata': 'testtest',
                'dict2': '%(map1)s': 'data': '%(map1)s', '%(map2)s': 'status': 'available'

mapping_dict= 
    "map1": "asdf",
    "map2": "qwerz",



def apply_placeholder(d, placeholder):
    for key, value in d.items():
        del d[key]
        if isinstance(value, dict):
            d[key % placeholder] = value
            apply_placeholder(value, placeholder)
        else:
            d[key % placeholder] = value % placeholder


apply_placeholder(example_dict, mapping_dict)
pprint(example_dict)

打印:

'dict1': 'asdf': 'data': 'tmp', 'qwerz': 'freshdata': 'testtest',
 'dict2': 'asdf': 'data': 'asdf', 'qwerz': 'status': 'available'

我不是特别喜欢del 调用和在这里修改输入对象,很高兴看到更好的选择。

【讨论】:

你可以在这里使用dict.pop吗? @NinjaPuppy 我觉得我正在接受面试,只是提出了一个糟糕的解决方案,面试官正试图帮助我指出正确的方向:) 对不起 - 不是那个意思 :) 诺诺,这只是我个人的恐惧/恐惧症和偶尔的主题噩梦。 还有一个问题:如果mapping_dict 包含数字(int)或列表(带int)并且我还想在输入dict 中有正确的数据类型,我需要更改什么? 【参考方案3】:

我认为这可以递归地做你想要的。它会创建原始字典的副本,然后对其进行修改,以便可以重复使用原始字典。

from pprint import pprint
import copy

try:
    stringtype = basestring
except NameError:
    stringtype = str  # Python 3

def subst(mapping, replacements):

    def do_subst(mapping, replacements):
        for k, v in list(mapping.items()):
            newk, newv = k, v
            changed = False

            if isinstance(k, stringtype):
                newk = k % replacements
                if newk != k:
                    changed = True

            if isinstance(v, stringtype):
                newv = v % replacements
                if newv != v:
                    changed = True
            elif isinstance(v, dict):
                newv = do_subst(v, replacements)
                if newv != v:
                    changed = True

            if changed:
                del mapping[k]
                mapping[newk] = newv

        return mapping

    return do_subst(copy.deepcopy(mapping), replacements)

example_dict = 'dict1': '%(map1)s': 'data': 'tmp',
                          '%(map2)s': 'freshdata': 'testtest',
                'dict2': '%(map1)s': 'data': '%(map1)s',
                          '%(map2)s': 'status': 'available'

mapping_dict= "map1": "asdf", "map2": "qwerz"

print('Before')
pprint(example_dict)
result = subst(example_dict, mapping_dict)
print('After')
pprint(result)

输出:

 Before
 'dict1': '%(map1)s': 'data': 'tmp', '%(map2)s': 'freshdata': 'testtest',
  'dict2': '%(map1)s': 'data': '%(map1)s',
            '%(map2)s': 'status': 'available'
 After
 'dict1': 'asdf': 'data': 'tmp', 'qwerz': 'freshdata': 'testtest',
  'dict2': 'asdf': 'data': 'asdf', 'qwerz': 'status': 'available'

【讨论】:

以上是关于用映射字典的值替换嵌套字典中的占位符的主要内容,如果未能解决你的问题,请参考以下文章

用 pom.xml 中的值替换占位符名称

用其他数组中的值替换数组中的占位符

如何将 R 会话中的值替换为 SQL 绑定变量占位符?

用点击的 span 标签的 innerHTML 替换占位符值

用 Chrome 中的自定义文本替换默认的 html5 日期占位符

用c#替换word文档中的占位符