代码之家  ›  专栏  ›  技术社区  ›  Markus

从Python中的列表创建JSON类型的嵌套字典

  •  2
  • Markus  · 技术社区  · 8 年前

    我希望从列表列表中创建一个JSON类型的嵌套字典。这些列表包含完整的目录路径,但我将它们分解为各自的组件,因为我认为这样可以更容易地创建嵌套字典。

    示例列表:

    ["root", "dir1", "file.txt"] 
    

    预期结果:

    {
        "type": "directory",
        "name": "root",
        "children": [
            {
                "type": "directory",
                "name": "dir1",
                "children": [
                    {
                        "type": "file",
                        "name": "file.txt",
                    }
                ]
            }
        ]
    }      
    

    我尝试过使用递归方法,但没有达到目的(对递归方法很陌生,我的脑袋一直在转)。我还尝试了一种迭代方法,从我在这里找到的一个想法(堆栈溢出),它反转列表并向后构建dict,我有点开始工作,但无法解决其中一个解决方案要求,即代码可以在遍历列表时处理部分目录路径中的重复。

    ["root", "dir1", "dir2", "file2.txt"]
    

    它需要在JSON字典的基础上生成:-

    {
        "type": "directory",
        "name": "root",
        "children": [
            {
                "type": "directory",
                "name": "dir1",
                "children": [
                    {
                        "type": "file",
                        "name": "file.txt",
                    }
                    {
                        "type": "directory",
                        "name": "dir2",
                        "children": [
                            {
                                "type": "file",
                                "name": "file2.txt"
                            }
                        ]
                    }
                ]
            }
        ]
    } 
    

    谢谢。

    3 回复  |  直到 8 年前
        1
  •  1
  •   slider    8 年前

    一种带参数的递推解法 itertools.groupby

    还要注意的是,目录中的文件名不能重复,因此所有文件都将按元素列表分组 groupby :

    from itertools import groupby
    from operator import itemgetter
    
    def build_dict(paths):
        if len(paths) == 1 and len(paths[0]) == 1:
            return {"type": "file", "name": paths[0][0]}
        dirname = paths[0][0]
        d = {"type": "directory", "name": dirname, "children": []}
        for k, g in groupby(sorted([p[1:] for p in paths], key=itemgetter(0)),
                            key=itemgetter(0)):
            d["children"].append(build_dict(list(g)))
        return d    
    
    paths = [["root", "dir1", "file.txt"], ["root", "dir1", "dir2", "file2.txt"]]
    print(build_dict(paths))
    

    {
      "type": "directory",
      "name": "root",
      "children": [
        {
          "type": "directory",
          "name": "dir1",
          "children": [
            {
              "type": "directory",
              "name": "dir2",
              "children": [
                {
                  "type": "file",
                  "name": "file2.txt"
                }
              ]
            },
            {
              "type": "file",
              "name": "file.txt"
            }
          ]
        }
      ]
    }
    
        2
  •  1
  •   ggorlen Hoàng Huy Khánh    8 年前

    path

    import json
    
    
    def path_to_json(path, root):
        if path:
            curr = path.pop(0)
    
            if not root:
                root["type"] = "file"
                root["name"] = curr
    
                if path:
                    root["children"] = [{}]
                    root["type"] = "directory"
                    path_to_json(path, root["children"][0])
            elif path:
                try:
                    i = [x["name"] for x in root["children"]].index(path[0])
                    path_to_json(path, root["children"][i])
                except ValueError:        
                    root["children"].append({})
                    path_to_json(path, root["children"][-1])
    
        return root
    
    
    if __name__ == "__main__":
        paths = [["root", "dir1", "file.txt"], 
                 ["root", "dir1", "dir2", "file2.txt"]]
        result = {}
        print(json.dumps([path_to_json(x, result) for x in paths][0], indent=4))
    

    输出:

    {
        "type": "directory",
        "name": "root",
        "children": [
            {
                "type": "directory",
                "name": "dir1",
                "children": [
                    {
                        "type": "file",
                        "name": "file.txt"
                    },
                    {
                        "type": "directory",
                        "name": "dir2",
                        "children": [
                            {
                                "type": "file",
                                "name": "file2.txt"
                            }
                        ]
                    }
                ]
            }
        ]
    }
    

    Try it!

        3
  •  0
  •   aydow    8 年前

    dict

    In [537]: structure = ["root", "dir1", "dir2", "file2.txt"]
    
    In [538]: d = {}
    
    # Create a reference to the current dict
    In [541]: curr = d
    
    In [542]: for i, s in enumerate(structure):
         ...:     curr['name'] = s
         ...:     if i != len(structure) - 1:
         ...:         curr['type'] = 'directory'
         ...:         curr['children'] = {}
         ...:         curr = curr['children']          # New reference is the child dict
         ...:     else:
         ...:         curr['type'] = 'file'
         ...:
    
    In [544]: from pprint import pprint
    
    In [545]: pprint(d)
    {'children': {'children': {'children': {'name': 'file2.txt', 'type': 'file'},
                               'name': 'dir2',
                               'type': 'directory'},
                  'name': 'dir1',
                  'type': 'directory'},
     'name': 'root',
     'type': 'directory'}
    

    我不知道这是否适用于你所有的问题,因为规格不是很详细