2017-06-14 137 views
1

我在这样的列表中有一个层次结构。 真正的层次结构更复杂,可能会有无限的嵌套深度,它不仅仅是地板上的房间。从列表中的层次结构创建嵌套字典

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', 
    } 
    } 
} 

我无法弄清楚如何把“名”叶与子树到同一字典。我得到的最接近的是这样的:

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': {}}, 
... 

我想我有修真改变这样的事情:

{ child['id']: build2(child['id']) for child in children } 

但随后我错过了叶节点('名称')

回答

1

这是我尝试重写您build功能:

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 
1

希望这是你想要的。

>>> 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" 
    } 
} 
>>> 

显示的顺序是不一样的,但这些字段与您的示例中所述完全相同。

1

不正是你想要的,但更通用。希望对你有用。

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))