【问题标题】:Create nested dictionary from a hierarchy in a list从列表中的层次结构创建嵌套字典
【发布时间】:2017-06-14 05:44:50
【问题描述】:

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

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 }

但是我错过了叶节点('name')

【问题讨论】:

    标签: python dictionary recursion


    【解决方案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 
    

    【讨论】:

      【解决方案2】:

      希望这是你想要的。

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

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          猜你喜欢
          • 2016-05-06
          • 2018-11-19
          • 2023-01-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-04-04
          • 2021-11-20
          • 2021-04-19
          相关资源
          最近更新 更多