【问题标题】:Convert list of path-like strings to nested dictionary of lists (arbitrary depth)将类似路径的字符串列表转换为列表的嵌套字典(任意深度)
【发布时间】:2022-10-13 22:24:04
【问题描述】:

以下是示例输入数据(实际数据可能比此处显示的级别更多,因此该解决方案应适用于任意深度):

['/SKA_20-VA-001/SKA_20-V-0546',
 '/SKA_20-VA-001/SKA_20-V-0148',
 '/SKA_20-VA-001/SKA_20-LT-0028A/SKA_20-LI-0028A',
 '/SKA_20-VA-001/SKA_20-LT-0028A/SKA_20-LI-0028B',
 '/SKA_20-VA-001/SKA_20-PT-0034/SKA_20-PI-0034',
 '/SKA_20-VA-001/SKA_20-V-0685',
 '/SKA_20-VA-001/SKA_20-V-0551']

我想把它变成一个嵌套字典来存储路径的层次结构,其中每个父目录都成为一个 dict 键,所有文件都成为列表中的元素。

期望的结果

{
  "SKA_20-VA-001": [
    "SKA_20-V-0546",
    "SKA_20-V-0148",
    "SKA_20-V-0685",
    "SKA_20-V-0551",
    {"SKA_20-LT-0028A": ["SKA_20-LI-0028A", "SKA_20-LI-0028B"]},
    {"SKA_20-PT-0034": ["SKA_20-PI-0034"]}
  ]
}

我遇到过this 的答案,但它并没有真正解决我的问题。或者我无法正确修改它。

【问题讨论】:

  • 您可以使用您提到的另一个线程中的方法,然后为仅包含一个元素的条目折叠字典。
  • 由于使用了 defaultdict 和 marcher,我很难理解其他代码。一个代码示例将不胜感激!
  • 您确定您想要的输出实际上是正确的吗?您对列表和字典的使用似乎非常不一致。
  • 让我仔细检查一下我是否犯了错误(编辑:更新了预期的结果)。我希望所有文件都存在于列表中,并且所有目录都是键。如果有更好的方式来表示层次结构,那么我对此持开放态度。

标签: python parsing recursion


【解决方案1】:

如果您将文件视为目录,则这样的结构更容易构建。构建后,您仍然可以将其转换为您正在寻找的列表/字典组合。

在这种情况下,没有任何子元素 ({}) 的元素应该是文件:

def add_path(tree, split_path):
    subtree = tree.setdefault(split_path[0], {})
    if len(split_path) > 1:
        add_path(subtree, split_path[1:])


def parse_tree(paths):
    tree = {}
    for path in paths:
        add_path(tree, path.split("/"))
    return tree


if __name__ == "__main__":
    print(parse_tree(
        ['/SKA_20-VA-001/SKA_20-V-0546',
         '/SKA_20-VA-001/SKA_20-V-0148',
         '/SKA_20-VA-001/SKA_20-LT-0028A/SKA_20-LI-0028A',
         '/SKA_20-VA-001/SKA_20-LT-0028A/SKA_20-LI-0028B',
         '/SKA_20-VA-001/SKA_20-PT-0034/SKA_20-PI-0034',
         '/SKA_20-VA-001/SKA_20-V-0685',
         '/SKA_20-VA-001/SKA_20-V-0551']
    ))

结果是

{
  "": {
    "SKA_20-VA-001": {
      "SKA_20-V-0546": {},
      "SKA_20-V-0148": {},
      "SKA_20-LT-0028A": {
        "SKA_20-LI-0028A": {},
        "SKA_20-LI-0028B": {}
      },
      "SKA_20-PT-0034": {
        "SKA_20-PI-0034": {}
      },
      "SKA_20-V-0685": {},
      "SKA_20-V-0551": {}
    }
  }
}

如果您需要帮助将此结构转换为您要求的确切结构,请告诉我。

【讨论】:

    【解决方案2】:

    包“extradict”有一个NestedData 类可以安排这个。 不幸的是,到目前为止,路径分隔符被硬编码为一个点 (.),这意味着您必须在输入数据之前替换数据中的/(并且还要去掉前导的/)。

    在那之后,我认为它可以做你需要的一切。如果您的叶子路径也是“路径”但映射到None,这将更简单 - 但如果您需要简单的字符串,也可以这样做。

    总而言之,代码是这样的:

    from extradict import NestedData
    
    data = ['/SKA_20-VA-001/SKA_20-V-0546',
     '/SKA_20-VA-001/SKA_20-V-0148',
     '/SKA_20-VA-001/SKA_20-LT-0028A/SKA_20-LI-0028A',
     '/SKA_20-VA-001/SKA_20-LT-0028A/SKA_20-LI-0028B',
     '/SKA_20-VA-001/SKA_20-PT-0034/SKA_20-PI-0034',
     '/SKA_20-VA-001/SKA_20-V-0685',
     '/SKA_20-VA-001/SKA_20-V-0551']
    
    d1 = [d.replace("/", ".") for d in data]
    d2 = NestedData(dict.fromkeys(d1))
    
    print(d2)
    

    将打印:

    {'SKA_20-VA-001': {
        'SKA_20-V-0546': <NoneType>,
        'SKA_20-V-0148': <NoneType>,
        'SKA_20-LT-0028A': {
            'SKA_20-LI-0028A': <NoneType>,
            'SKA_20-LI-0028B': <NoneType>},
        'SKA_20-PT-0034': {'SKA_20-PI-0034': <NoneType>},
        'SKA_20-V-0685': <NoneType>,
        'SKA_20-V-0551': <NoneType>}}
    

    如果您需要将数据结构作为普通 dicts,只需在 d2 上使用 .data 属性:

    In [33]: print(d2.data)
    {'SKA_20-VA-001': {'SKA_20-V-0546': None, 'SKA_20-V-0148': None, 'SKA_20-LT-0028A': {'SKA_20-LI-0028A': None, 'SKA_20-LI-0028B': None}, 'SKA_20-PT-0034': {'SKA_20-PI-0034': None}, 'SKA_20-V-0685': None, 'SKA_20-V-0551': None}}
    

    免责声明:我是extradict 的作者。您可以使用pip install extradict 安装它 - 当前版本为 0.6

    【讨论】:

      猜你喜欢
      • 2018-07-22
      • 2016-02-08
      • 1970-01-01
      • 1970-01-01
      • 2021-11-25
      • 1970-01-01
      • 2022-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多