修改嵌套词典

时间:2013-07-05 05:24:40

标签: python dictionary

鉴于这两个方面:

empty = {'151': {'1': 'empty', '0': 'empty', '2': '2.30'}}
full = {'151': {'1': 3.4, '0': 3.6, '2': 2}}

首先,我想检查empty.keys() == full.keys()是否成立,我想将empty值替换为full字典中的相应值。它应该导致:

not_empty = {'151': {'1': '3.4', '0': '3.6', '2': '2.30'}}

到目前为止我的解决方案:我认为我会使用正则表达式识别所有具有empty值的键,但无论出于何种原因,我的代码到目前为止都会生成一个空的字典{}

import re 
find_empty = re.findall("'(\d)':\s'empty'", str(empty))[0]

if empty.keys() == full.keys():
    k = empty.values()[0].keys()
    v = empty.values()[0].values()
    print {k:v for k,v in empty.values()[0].iteritems()\
                   if empty.values()[0][find_empty] != 'empty'}

我希望它可以输出{'151': {'2': '2.30'}}作为一个好的起点。无论如何,我想这个任务存在更多干净的解决方案然后正则表达式,所以欢迎任何提示!

1 个答案:

答案 0 :(得分:3)

正则表达式不适合这项工作。我建议采用如下的递归方法。

empty = {'151': {'1': 'empty', '0': 'empty', '2': '2.30'}}
full = {'151': {'1': 3.4, '0': 3.6, '2': 2}}

def repl(a, b):
    clean = {}
    for k, v in a.items():
        # This is the case where we want to replace what we have in b if we have something.  Just in case, use the dict.get method and provide a default.
        if v == 'empty': 
            clean[k] = b.get(k, 'Not there')
        # If the value is another dict, then call this function with the value, and put the return as the value for our current key
        elif isinstance(v, dict):
            v_clean = repl(v, b.get(k, {}))
            clean[k] = v_clean
        # The value isn't equal to 'empty', and it isn't another dict, so just keep the current value.
        else:
            clean[k] = v
    # Finally, return the cleaned up dictionary.
    return clean

print repl(empty, full)

<强>输出

{'151': {'1': 3.4, '0': 3.6, '2': '2.30'}}

编辑我不确定这是否能解决您的所有情况,但无论如何它都值得一看。

empty = {'151': {'1': 'empty', '0': 'empty', '2': '2.30', '8': ['empty', 'empty', 5, {"foo2": "bar2", "1": "empty"}]}}
full = {'151': {'1': 3.4, '0': 3.6, '2': 2, '8': ['foo', 'bar', 'baz', {"foo3": "bar3", "1": "2"}]}}

def repl(a, b):
    if isinstance(a, dict) and isinstance(b, dict):
        clean = {}
        for k, v in a.items():
            # This is the case where we want to replace what we have in b if we have something.  Just in case, use the dict.get method and provide a default.
            if v == 'empty':
                clean[k] = b.get(k, 'Not there')
            # If the value is another dict, then call this function with the value, and put the return as the value for our current key
            elif isinstance(v, dict):
                v_clean = repl(v, b.get(k, {}))
                clean[k] = v_clean
            # The value isn't equal to 'empty', and it isn't another dict, so just keep the current value.
            elif isinstance(v, list):
                v_clean = repl(v, b.get(k, []))
                clean[k] = v_clean
            else:
                clean[k] = v
        # Finally, return the cleaned up dictionary.
    elif isinstance(a, list) and isinstance(b, list):
        clean = []
        for item_a, item_b in zip(a, b):
            if item_a == 'empty':
                clean.append(item_b)
            elif isinstance(item_a, dict):
                clean_a = repl(item_a, item_b)
                clean.append(clean_a)
            else:
                clean.append(item_a)
    return clean

print repl(empty, full)

<强>输出

{'151': {'1': 3.4, '0': 3.6, '2': '2.30', '8': ['foo', 'bar', 5, {'1': '2', 'foo2': 'bar2'}]}}