根据键修改嵌套字典中的值

时间:2016-03-14 02:10:53

标签: python dictionary

我有以下词典:

input_processed = {'units' : {'g' : 'g',
                              'dx' : 'cm',
                              'po' : 'bar',
                              'muo' : 'mPas'},
                   'g' : 1.0,
                   'dx' : [10.0, 20.0, 10.0],
                   'muo' : {'po' : [0.0, 1.0],
                            'muo' : [32.7, 32.7]},
                   'phi' : 0.05}

commands_variables = {'units' : [],
                      'g' : ['g'],
                      'dx' : ['dx'],
                      'muo' : ['po', 'muo'],
                      'phi' : ['phi']}

conversion_factors = {'g' : 9.81,
                      'cm' : 0.01,
                      'bar' : 10**5,
                      'mPas' : 10**-3}

我的目标是将input_processed中的每个浮点数乘以conversion_factors中为某些变量定义的因子。由于命令(input_processed中的最高级别键可以定义多个变量,因此这些变量将映射到commands_variables

首先,我需要检查input_processed['units']中是否包含变量,因为phi没有单位。然后对于每个命令中的每个变量,我需要获得该单元。在下一步中,我将根据conversion_factors中的单位获得转换因子。由于input_processed中最高级别键的值可以是float,list或dict类型,因此我为每种情况编写了不同的方法。这被放入一个函数中,并在input_processed的循环中调用。

def convert_unit(data, command, parameter):
    for it in commands_variables[command]:
        if it in data['units']:
            variable = it
        else:
            continue

        unit = data['units'][variable]
        conversion_factor = conversion_factors[unit]

        if type(parameter) is float:
            converted = parameter*conversion_factor
        elif type(parameter) is list:
            converted = [parameter[it]*conversion_factor
                         for it in range(len(parameter))]
        elif type(parameter) is OrderedDict:
            for key, value in parameter.items():
                value = parameter[key]
                converted = [value[it]*conversion_factor
                             for it in range(len(value))]

        return converted

input_converted = {}
for key, value in input_processed.items():
    input_converted[key] = convert_unit(input_processed, key, value)

所需的输出用于功能

9.81
[0.1, 0.2, 0.1]
{'po' : [0.0, 100000.0], 'muo' : [0.0327, 0.0327]}
0.05

和主程序

input_processed = {'units' : {'g' : 'g',
                              'dx' : 'cm',
                              'po' : 'bar',
                              'muo' : 'mPas'},
                   'g' : 9.81,
                   'dx' : [0.1, 0.2, 0.1],
                   'muo' : {'po' : [0.0, 100000.0],
                            'muo' : [0.0327, 0.0327]},
                   'phi' : 0.05}

我设法转换浮点数和列表但没有字典。在这个缩短的问题陈述中,我得到了局部变量'转换的错误。在分配之前引用。

如果某人有更简单的方法来转换数量,我将不胜感激。

1 个答案:

答案 0 :(得分:0)

现有代码的主要问题是您的

for key, value in parameter.items():

循环没有在嵌套字典中累积更改的项目,因此代码的该部分生成的converted将只是item中转换的最后parameter;此部分仅处理作为列表的嵌套字典项,它将在普通浮点数上失败。

FWIW,主return converted循环底部的for看起来有点可疑:循环内的无条件return会导致函数在第一个循环结束时返回循环迭代。这真的很好,因为我们想要在我们获得成功的匹配it in data['units']之后退出循环,但是对于阅读代码的人来说它仍然有点棘手。 :)

一个小问题是使用type进行类型测试。建议您改用isinstance。有关详细信息,请参阅Differences between isinstance() and type() in python。正如答案中提到的那样,尽可能避免type尽可能地检查Python,因为这会干扰鸭子打字。

无论如何,这是您的功能的修改版本。我的代码在Python 2.6.6上进行了测试,但它应该在Python 3上正确执行...我想。 :)

from pprint import pprint

conversion_factors = {
    'g' : 9.81,
    'cm' : 0.01,
    'bar' : 10**5,
    'mPas' : 10**-3
}

input_processed = {
    'units' : {
        'g' : 'g',
        'dx' : 'cm',
        'po' : 'bar',
        'muo' : 'mPas'
    },
    'g' : 1.0,
    'dx' : [10.0, 20.0, 10.0],
    'muo' : {
        'po' : [0.0, 1.0],
        'muo' : [32.7, 32.7]
    },
    'phi' : 0.05
}

def convert_dict(indata):
    units = indata['units']

    def convert(key, item):
        factor = conversion_factors.get(units.get(key))
        if factor is not None:
            if isinstance(item, list):
                item = [u * factor for u in item]
            else:
                item *= factor
        return item

    outdata = {'units': units.copy()}
    for k, v in indata.items():
        if k == 'units':
            continue
        if isinstance(v, dict):
            outdata[k] = newd = {}
            for k1, v1 in v.items():
                newd[k1] = convert(k1, v1)
        else:
            outdata[k] = convert(k, v)

    return outdata

input_converted = convert_dict(input_processed)
pprint(input_converted)

<强>输出

{'dx': [0.10000000000000001, 0.20000000000000001, 0.10000000000000001],
 'g': 9.8100000000000005,
 'muo': {'muo': [0.032700000000000007, 0.032700000000000007],
         'po': [0.0, 100000.0]},
 'phi': 0.050000000000000003,
 'units': {'dx': 'cm', 'g': 'g', 'muo': 'mPas', 'po': 'bar'}}

FWIW,虽然pprint.pprint可以显示字典,但您可以使用json.dumps获得更漂亮的输出。