将列表转换为嵌套列表和dicts

时间:2011-10-10 06:10:39

标签: python

我有一组与此类似的数据:

[  {"name":"item.key" , "value":"value"},
   {"name":"item.key2" , "value":"value2"},
   {"name":"item.list.0" , "value":"listValue1"},
   {"name":"item.list.1" , "value":"listValue2"},
   {"name":"item.list.2" , "value":"listValue3"},·
   {"name":"item.list2.0.key1" , "value":"list2Key1Value"},
   {"name":"item.list2.0.key2" , "value":"list2Key2Value"},
   {"name":"item.list2.0.key3" , "value":"list2Key3Value"},·
   {"name":"item.list3.0.key1" , "value":"list3Key1Value"},
   {"name":"item.list3.0.key2" , "value":"list3Key2Value"},
   {"name":"item.list3.0.key3" , "value":"list3Key3Value"},
   {"name":"other.key" , "value":"otherKeyValue"}
]

名称从包含列表和dicts的嵌套数据中展平。我现在想把它放回到dicts和list(在适当的地方)。

到目前为止,我有这个:

obj = {}
def addObj(o, path, value):
    if len(path) > 1:
        o = o.setdefault(path.pop(0), {})
        addObj(o, path, value)
    else:
        o[path.pop(0)] = value

for item in data:
    parts = item['name'].split(".")
    addObj(obj, parts, item['value'])

这会产生这个:

{'item': {
     'key': 'value',
     'key2': 'value2',
     'list': {
         '0': 'listValue1',
         '1': 'listValue2',
         '2': 'listValue3'},
     'list2': {
         '0': {
             'key1': 'list2Key1Value',
             'key2': 'list2Key2Value',
             'key3': 'list2Key3Value'}
     },
     'list3': {
         '0': {
             'key1': 'list3Key1Value',
             'key2': 'list3Key2Value',
             'key3': 'list3Key3Value'}
     }
 },
 'other': {'key': 'otherKeyValue'}
}

但是现在,我想要任何具有可以全部转换为int的键的dict转换为列表,所以我的最终输出看起来更像:

{'item': {
     'key': 'value',
     'key2': 'value2',
     'list': [
         'listValue1',
         'listValue2',
         'listValue3'],
     'list2': [{'key1': 'list2Key1Value',
             'key2': 'list2Key2Value',
             'key3': 'list2Key3Value'}],
     'list3': [{'key1': 'list3Key1Value',
             'key2': 'list3Key2Value',
             'key3': 'list3Key3Value'}]
 },
 'other': {'key': 'otherKeyValue'}
}

关于如何实现这一目标的任何建议?

4 个答案:

答案 0 :(得分:2)

这可能不是最有效的方法,但是......

import pprint

data = [{"name":"item.key" , "value":"value"},
   {"name":"item.key2" , "value":"value2"},
   {"name":"item.list.0" , "value":"listValue1"},
   {"name":"item.list.1" , "value":"listValue2"},
   {"name":"item.list.2" , "value":"listValue3"},
   {"name":"item.list2.0.key1" , "value":"list2Key1Value"},
   {"name":"item.list2.0.key2" , "value":"list2Key2Value"},
   {"name":"item.list2.0.key3" , "value":"list2Key3Value"},
   {"name":"item.list3.0.key1" , "value":"list3Key1Value"},
   {"name":"item.list3.0.key2" , "value":"list3Key2Value"},
   {"name":"item.list3.0.key3" , "value":"list3Key3Value"},
   {"name":"other.key" , "value":"otherKeyValue"}]

obj = {}
def addObj(o, path, value):
    if len(path) > 1:
        o = o.setdefault(path.pop(0), {})
        addObj(o, path, value)
    else:
        o[path.pop(0)] = value

for item in data:
    parts = item['name'].split(".")
    addObj(obj, parts, item['value'])

# this function assumes all keys are strings
def convert(obj):
    if isinstance(obj, dict):
        if all(key.isdigit() for key in obj.keys()):
            return [convert(obj[key])
                    for key in sorted(obj.keys(), key=int)]
        return dict((key, convert(value)) for key, value in obj.items())
    return obj

pprint.pprint(convert(obj))

生成以下输出:

{'item': {'key': 'value',
          'key2': 'value2',
          'list': ['listValue1', 'listValue2', 'listValue3'],
          'list2': [{'key1': 'list2Key1Value',
                     'key2': 'list2Key2Value',
                     'key3': 'list2Key3Value'}],
          'list3': [{'key1': 'list3Key1Value',
                     'key2': 'list3Key2Value',
                     'key3': 'list3Key3Value'}]},
 'other': {'key': 'otherKeyValue'}}

答案 1 :(得分:1)

您可以更改genexp以更好地满足您的需求(可能不是您的真实数据),但这样可行:

for v in d.values():
    for key in (i for i in v if i.startswith('list')):
        v[key] = list(v[key].values())

现在d字典包含您想要的内容

答案 2 :(得分:1)

您可以递归遍历所有词典,并检查是否所有键都可以使用此转换为整数:

map(int, your_dict.keys())

如果其中一个密钥无法转换为ValueError,则会生成int

请注意,这不会检查键是否是连续的整数,也不会检查它们是否从0开始,因此在将字典转换为列表时可能会浪费大量空间。

答案 3 :(得分:0)

这是一个不完整的实现,只是为了证明这个想法:

class A:
    def __init__(self, h):
        self.h = dict(zip(map(int, h.keys()), h.values()))
def __getitem__(self, i): return self.h.get(i)
那么您可以使用此类型来表示列表。