将点分隔的字符串转换为嵌套的复杂字典

时间:2016-12-01 21:46:59

标签: python dictionary

作为一名java开发人员,我需要一些技巧如何在python 2中解决这个问题。我在python中的技能处于初始状态。但现在问题是:

我们为设备提供服务,这些设备以一种格式报告一些技术统计数据,我们无法更改。服务器运行python。 主要报告以字典形式出现,我们需要保存json方式。从dict到json的转换不是问题,但转换平面并使用点分隔键需要转换。

也许一个例子可以说明我想说的话。这是来自设备的格式,将其命名为:

{
    'Device.DeviceInfo.SoftwareVersion': 'ote-2.2.1',
    'Device.GatewayInfo.ProductClass': 'OEM-TX23',
    'Device.GatewayInfo.SerialNumber': 'A223142D1CC7',

    'Device.Ethernet.Interface.1.MaxBitRate': 1000,

    'Device.HomePlug.Interface.1.AssociatedDevice.1.RxPhyRate': 522,
    'Device.HomePlug.Interface.1.AssociatedDevice.1.TxPhyRate': 706,
    'Device.HomePlug.Interface.1.AssociatedDevice.1.Active': 1,
    'Device.HomePlug.Interface.1.AssociatedDevice.1.MACAddress': 'af:49:79:e4:64:fc',

    'Device.HomePlug.Interface.1.AssociatedDevice.2.RxPhyRate': 544,
    'Device.HomePlug.Interface.1.AssociatedDevice.2.TxPhyRate': 0,
    'Device.HomePlug.Interface.1.AssociatedDevice.2.Active': 1,
    'Device.HomePlug.Interface.1.AssociatedDevice.2.MACAddress': 'af:49:79:e4:64:dd',


    'Device.Ethernet.Interface.2.MaxBitRate': 1000,

    'Device.HomePlug.Interface.2.AssociatedDevice.1.RxPhyRate': 671,
    'Device.HomePlug.Interface.2.AssociatedDevice.1.TxPhyRate': 607,
    'Device.HomePlug.Interface.2.AssociatedDevice.1.Active': 1,
    'Device.HomePlug.Interface.2.AssociatedDevice.1.MACAddress': 'bf:49:79:e4:64:fc',

    'Device.HomePlug.Interface.2.AssociatedDevice.2.RxPhyRate': 340,
    'Device.HomePlug.Interface.2.AssociatedDevice.2.TxPhyRate': 0,
    'Device.HomePlug.Interface.2.AssociatedDevice.2.Active': 1,
    'Device.HomePlug.Interface.2.AssociatedDevice.2.MACAddress': 'bf:49:79:e4:64:dd'
}

源中的Integer值表示此接口的接口索引和AssociatedDevices。因此,整数背后的部分应该是多个词典列表。结果中不应包含的整数值

我们需要以下嵌套结构才能将它持久保存到数据库,尤其是mysql docstore。再次,从嵌套dict到json的转换不是问题。

以下是我们需要的格式:

{
    'Device': {
        'GatewayInfo': {
            'SerialNumber': 'A223142D1CC7',
            'ProductClass': 'OEM-TX23'
        },
        'DeviceInfo': {
            'SoftwareVersion': 'ote-2.2.1'
        },
        'Ethernet': {
            'Interface': [{
                'MaxBitRate': 1000
            }, {
                'MaxBitRate': 1000
            }]
        },
        'HomePlug': {
            'Interface': [{
                'AssociatedDevice': [{
                    'RxPhyRate': 522,
                    'TxPhyRate': 706,
                    'Active': 1,
                    'MACAddress': 'af:49:79:e4:64:fc',
                }, {
                    'RxPhyRate': 544,
                    'TxPhyRate': 0,
                    'Active': 1,
                    'MACAddress': 'af:49:79:e4:64:dd',
                }]
            }, {
                'AssociatedDevice': [{
                    'RxPhyRate': 671,
                    'TxPhyRate': 607,
                    'Active': 1,
                    'MACAddress': 'bf:49:79:e4:64:fc',
                }, {
                    'RxPhyRate': 340,
                    'TxPhyRate': 0,
                    'Active': 1,
                    'MACAddress': 'bf:49:79:e4:64:dd',
                }]
            }]
        }
    }
}

更新 第一个答案是部分正确的,除了整数之后的部分应转换为包含其余为字典的列表。

3 个答案:

答案 0 :(得分:3)

您可以迭代原始字典以递归方式添加keys并将值添加到最终项目中:

new_dict = {}
for key, value in my_dict.items():
    k_list = key.split('.')
    temp_dict = new_dict
    for k in k_list[:-1]:
        if k not in temp_dict:
            temp_dict[k] = {}
        temp_dict = temp_dict[k]
    temp_dict[k_list[-1]] = value

其中my_dict是您提到的原始dict对象。

new_dict持有的最终价值为:

{
   "Device":{
      "GatewayInfo":{
         "SerialNumber":"A223142D1CC7",
         "ProductClass":"OEM-TX23"
      },
      "DeviceInfo":{
         "SoftwareVersion":"ote-2.2.1"
      },
      "HomePlug":{
         "Interface":{
            "1":{
               "AssociatedDevice":{
                  "1":{
                     "RxPhyRate":522,
                     "Active":1,
                     "TxPhyRate":706,
                     "MACAddress":"af:49:79:e4:64:fc"
                  },
                  "2":{
                     "Active":1,
                     "MACAddress":"af:49:79:e4:64:dd",
                     "RxPhyRate":544,
                     "TxPhyRate":0
                  }
               }
            },
            "2":{
               "AssociatedDevice":{
                  "1":{
                     "RxPhyRate":671,
                     "Active":1,
                     "TxPhyRate":607,
                     "MACAddress":"bf:49:79:e4:64:fc"
                  },
                  "2":{
                     "RxPhyRate":340,
                     "MACAddress":"bf:49:79:e4:64:dd",
                     "TxPhyRate":0,
                     "Active":1
                  }
               }
            }
         }
      },
      "Ethernet":{
         "Interface":{
            "1":{
               "MaxBitRate":1000
            },
            "2":{
               "MaxBitRate":1000
            }
         }
      }
   }
}

答案 1 :(得分:1)

这应该有效。只需将未转换的dict传递给convert,它就会返回转换后的dict

def convert(data):
    to_convert = set()
    new_dict = {}
    for key, value in data.items():
        path_stack = []
        k_list = key.split('.')
        temp_dict = new_dict
        for k in k_list[:-1]:
            path_stack.append(k)
            if k.isnumeric():
                to_convert.add(tuple(path_stack))
            if k not in temp_dict:
                temp_dict[k] = {}
            temp_dict = temp_dict[k]
        temp_dict[k_list[-1]] = value

    for path in sorted(to_convert, key=len, reverse=True):
        current_level = new_dict
        for k in path[:-2]:
            current_level = current_level[k]
        if isinstance(current_level[path[-2]], dict):
            new_level = [current_level[path[-2]][i] for i in sorted(current_level[path[-2]].keys())]
        else:
            new_level = current_level[path[-2]]
        current_level[path[-2]] = new_level

    return new_dict

答案 2 :(得分:0)

如果你想深入了解python,你可能会对模块dotteddict感兴趣。

这是一个有点棘手但非常有趣的“pythonic”代码。在某个时刻,它不会将数字键转换为列表,但其中的一些概念绝对值得花时间。