【问题标题】: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;直到你得到一个字符串或不可迭代的类型......你有什么问题?
  • 列表不能是字典键。除非您要使用列表的字符串表示形式。

标签: dictionary nested string-formatting python-3.5


【解决方案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'}}}
    

    【讨论】:

      猜你喜欢
      • 2016-01-07
      • 2013-04-30
      • 2023-01-23
      • 2017-07-28
      • 2019-09-06
      • 1970-01-01
      • 2012-04-26
      • 1970-01-01
      • 2021-04-21
      相关资源
      最近更新 更多