Python 从列表中的层次结构创建嵌套字典

Python 从列表中的层次结构创建嵌套字典,python,dictionary,recursion,Python,Dictionary,Recursion,我在这样的列表中有一个层次结构。 真正的层次结构更为复杂,嵌套的深度可能是无限的,而不仅仅是楼层中的房间 locations = [ { "loc": "root", "id": "floor_1", "name": "floor_1 name" }, { "loc": "root", "id": "floor_2", "name": "floor_2 name" },

我在这样的列表中有一个层次结构。 真正的层次结构更为复杂,嵌套的深度可能是无限的,而不仅仅是楼层中的房间

locations = [
    {
        "loc": "root",
        "id": "floor_1",
        "name": "floor_1 name"
    },
    {
        "loc": "root",
        "id": "floor_2",
        "name": "floor_2 name"
    },
    {
        "loc": "floor_1",
        "id": "room_1-1",
        "name": "room_1-1 name"
    },
    {
        "loc": "floor_1",
        "id": "room_1-2",
        "name": "room_1-2 name"
    },
    {
        "loc": "floor_2",
        "id": "room_2-1",
        "name": "room_2-1 name"
    }
我需要将其转换为嵌套字典,如下所示:

{
  'floor_1': {
    'name': 'floor_1 name',
    'room_1-1': {
      'name': 'room_1-1 name',
    },
    'room_1-2': {
      'name': 'room_1-2 name',
    }
  },
  'floor_2': {
    'name': 'floor_2 name',
    'room_2-1': {
      'name': 'room_2-1 name',
    }
  }
}
{ child['id']: build2(child['id']) for child in children }
我不知道如何将“名称”叶和子树放在同一个目录中。最接近的是:

def build(loc):
    children = filter(lambda l: l['loc'] == loc, locations)
    return {
        child['id']: {
            'name': child['name'],
            'xxx': build(child['id'])
        }
        for child in children
    }
build('root')
这显然会产生错误的输出:

{'floor_1': {'name': 'floor_1 name',
             'xxx': {'room_1-1': {'name': 'room_1-1 name', 'xxx': {}},
...
我想我必须把理解改成这样:

{
  'floor_1': {
    'name': 'floor_1 name',
    'room_1-1': {
      'name': 'room_1-1 name',
    },
    'room_1-2': {
      'name': 'room_1-2 name',
    }
  },
  'floor_2': {
    'name': 'floor_2 name',
    'room_2-1': {
      'name': 'room_2-1 name',
    }
  }
}
{ child['id']: build2(child['id']) for child in children }

但是我缺少了叶节点('name')

希望这就是您想要的

>>> layout = { i['id'] : {"name" : i['name']} for i in locations if 'floor' in i['id'] }
>>>
>>> for i in locations:
...     if i['loc'] in layout:
...         layout[i['loc']].update({i['id'] : { "name" : i['name']}})
...
>>> import json; print(json.dumps(layout, indent=2))
{
  "floor_1": {
    "room_1-2": {
      "name": "room_1-2 name"
    },
    "name": "floor_1 name",
    "room_1-1": {
      "name": "room_1-1 name"
    }
  },
  "floor_2": {
    "room_2-1": {
      "name": "room_2-1 name"
    },
    "name": "floor_2 name"
  }
}
>>>

显示的顺序不同,但字段与示例中所述的完全相同。

以下是我试图重写
构建
函数的尝试:

def build(loc_key):

    children = [(item['id'], item['name']) for item in locations if item['loc'] == loc_key]

    data = {}
    for key, name in children:
        data[key] = {'name': name}
        for item in locations:
            if item['loc'] == key:
                data[key].update(build(key))

    return data 

不完全是你想要的,但更一般。希望对你有用

import json


class TableDict(dict):
    """Table like data inside nested dictionary."""

    def __init__(self, **kwargs):
        super(TableDict, self).__init__({})
        self.keyorder = kwargs['keyorder']
        self.group_map = kwargs['group_map']

    def import_dictlist(self, dlist):
        """Import iterable of dictionaries."""
        for d in dlist:
            ptr = None
            for k in self.keyorder:
                val = d.pop(k)
                if ptr is None:
                    if val not in self:
                        self.update({val: {}})
                    ptr = self[val]
                else:
                    if val not in ptr:
                        ptr.update({val: {}})
                    ptr = ptr[val]
                self._get_dict_by_keys(ptr, d, k)
            if bool(d) is True:
                ptr.update({'values': d})

    def _get_dict_by_keys(self, t_d, d, key):
        """Add group keys to nested dict."""
        result = {}
        if key in self.group_map:
            for k in self.group_map[key]:
                if k in d:
                    result.update({k: d.pop(k)})
            if bool(result) is True:
                #t_d.update({'values': result})
                t_d.update(result)


if __name__ == '__main__':

    locations = [{'id': 'floor_1', 'name': 'floor_1 name', 'loc': 'root'},
                 {'id': 'floor_2', 'name': 'floor_2 name', 'loc': 'root'},
                 {'id': 'room_1-1', 'name': 'room_1-1 name', 'loc': 'floor_1'},
                 {'id': 'room_1-2', 'name': 'room_1-2 name', 'loc': 'floor_1'},
                 {'id': 'room_2-1', 'name': 'room_2-1 name', 'loc': 'floor_2'}]
    d = {'keyorder': ['loc', 'id'],
         'group_map': {'id':['name']}}

    td = TableDict(**d)
    td.import_dictlist(locations)

    print(json.dumps(td, indent =3))