2016-09-05 32 views
1

我有一个嵌套字典,它可以包含键和值中的占位符。用嵌套字典替换占位符与映射字典的值

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" 
} 

如果占位符是在价值定位,它也有可能发生的是,mapping_dict的相应的映射包含其它数据类型比字符串作为值,例如列表或int。我怎样才能将这个数据类型传递给原始字典?我不知道如何制作占位符,例如为一个列表。

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

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

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

+0

这是一个简单的(a)迭代-上垒型,(b)中检查项目型,(C)转到一个;直到你得到一个字符串或一个不可迭代的类型...你遇到了什么问题? – thebjorn

+0

列表不能是字典键。除非你打算使用列表的字符串表示。 –

回答

2

使用堆栈导航键值对,你可以弹出键来重新命名他们的价值观,同样动作,除了尝试,看看你能不能评价他们作为Python文字使用ast.literal_eval来处理你的列表大小写。

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调用和修改在这里输入对象,并乐意看到更好的选择。

+0

你可以在这里使用'dict.pop'吗? –

+0

@NinjaPuppy我觉得我在接受采访时,只是提出了一个可怜的解决方案,面试官正试图帮助我指引我进入正确的方向:) – alecxe

+0

对不起 - 不是这个意思:) –

1

我认为这是做你想要的,递归。它创建一个原始字典的副本,然后修改它,以便原始可以重用。

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'}}}