在Python中展平嵌套的JSON层次结构

2024-06-30 16:47:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我将以“无论如何我不是开发人员”作为开场白,但我被抛出了这项任务,我只是迷失了方向。这是我7年多来第一次使用python,也是第一次编写代码,但进展并不顺利。在

我所拥有的JSON是一个组织树,其中每个级别都可能在其下面有子级。在

我需要在Jupyter笔记本中用Python编写一个脚本,将其展平成这种格式,或者类似的格式,其中每个新的子元素都是一个新行。在

 level1 | level2 | level3
 org1
 org1      org2
 org1      org2    org3

以下是JSON:

^{pr2}$

我已经尝试了各种for循环,并在互联网上搜索了好几天,但我想我缺少一些非常基本的知识来实现这个功能。如果有人能提供任何帮助,我将不胜感激。在

以下是我的开场白:

for item in orgs_json:
    orgs_json_children = item["Children"]
    orgs_list.append(orgs_json_children)

或者

wanted = ['Children', 'Name']

for item in orgs_json[0]:
    details = [X["Name"] for X in orgs_json]
    for key in wanted:
        print(key, ':', json.dumps(details[key], indent=4))
    # Put a blank line at the end of the details for each item
    print()   

Tags: keynameinjsonfor格式detailsitem
3条回答

一个json递归树可以有多个根,叶不应该强制指定void children。例如,这里有一棵树,它有两个根“a”和“b”,节点只有一个“level”数据,即节点深度(“children”是可选的):

json_struct = [
    {
    'level': 'a0',
    'children': [{'level': 'a0.1',  'children':
                    [{'level': 'a0.1.1', 'children': []}]},
                 {'level': 'a0.2',  'children': [
                     {'level': 'a0.2.1', 'children': [
                            {'level': 'a0.2.1.1'},
                            {'level': 'a0.2.1.2'},
                            {'level': 'a0.2.1.3'},
                            {'level': 'a0.2.1.4', 'children': [{'level': 'a0.2.1.4.1'}, {'level': 'a0.2.1.4.2'}]}
                            ]
                        }
                    ]
                  },
                 {'level': 'a0.3', 'children': []},
                 {'level': 'a0.4', 'children': [{'level': 'a0.4.1'}, {'level': 'a0.4.2', 'children': []}]}
                ]
    },
    {
        'level': 'b0',
        'children': [{'level': 'b0.1', 'children': [{'level': 'b0.1.1'}]},
                     {'level': 'b0.2', 'children': [{'level': 'b0.2.1', 'children': [
                         {'level': 'b0.2.1.1'},
                         {'level': 'b0.2.1.2'},
                         {'level': 'b0.2.1.3', 'children': [{'level': 'b0.2.1.3.1'}, {'level': 'b0.2.1.3.2'}]},
                         {'level': 'b0.2.1.4'}
                            ]
                        }]},
                     {'level': 'b0.3'}
                     ]
    }
]

代码必须返回叶和完整的分支路径,直到每次离开:

^{pr2}$

它显示:

  1. 叶:a0.1.1路径:a0->;a0.1->;a0.1.1
  2. 叶:a0.2.1.1路径:a0->;a0.2->;a0.2.1->;a0.2.1.1
  3. 叶:a0.2.1.2路径:a0->;a0.2->;a0.2.1->;a0.2.1.2
  4. 叶:a0.2.1.3路径:a0->;a0.2->;a0.2.1->;a0.2.1.3
  5. 叶:a0.2.1.4.1路径:a0->;a0.2->;a0.2.1->;a0.2.1.4->;a0.2.1.4.1
  6. 叶:a0.2.1.4.2路径:a0->;a0.2->;a0.2.1->;a0.2.1.4->;a0.2.1.4.2
  7. 叶:a0.3路径:a0->;a0.3
  8. 叶:a0.4.1路径:a0->;a0.4->;a0.4.1
  9. 叶:a0.4.2路径:a0->;a0.4->;a0.4.2
  10. 叶:b0.1.1路径:b0->;b0.1->;b0.1.1
  11. 叶:b0.2.1.1路径:b0->;b0.2->;b0.2.1->;b0.2.1.1
  12. 叶:b0.2.1.2路径:b0->;b0.2->;b0.2.1->;b0.2.1.2
  13. 叶:b0.2.1.3.1路径:b0->;b0.2->;b0.2.1->;b0.2.1.3->;b0.2.1.3.1
  14. 叶:b0.2.1.3.2路径:b0->;b0.2->;b0.2.1->;b0.2.1.3->;b0.2.1.3.2
  15. 叶:b0.2.1.4路径:b0->;b0.2->;b0.2.1->;b0.2.1.4
  16. 叶:b0.3路径:b0->;b0.3

可以使用堆栈处理嵌套结构:

  • 从最外层的列表开始,reversed作为堆栈,每个列表都有一个空元组,以跟踪组织路径。在
  • while stack:循环中,从堆栈中获取顶层元素。做你需要做的事情,比如记录名字。从添加了当前组织名称的组织路径中生成一行。在
  • Children键中的所有元素与父组织的组织路径一起添加到堆栈中。在
  • 循环直到堆栈完成。在

需要反转,因为从堆栈中获取元素的顺序是相反的。您仍然希望将堆栈用于此作业(而不是队列),因为我们希望首先输出信息深度。在

这看起来像这样:

def flatten_orgs(orgs):
    stack = [(o, ()) for o in reversed(orgs)]  # organisation plus path
    while stack:
        org, path = stack.pop()  # top element
        path += (org['Name'],)   # update path, adding the current name
        yield path               # give this path to the caller
        # add all children to the stack, with the current path
        stack += ((o, path) for o in reversed(org['Children']))

然后可以循环上述函数以获取所有路径:

^{pr2}$

可以递归地对数据进行迭代。Prefix表示到目前为止看到的名称列表,data表示您还必须学习的词法列表。在

data = [{
    "Id": "f035de7f",
    "Name": "Org1",
    "ParentId": None,
    "Children": [{
        "Id": "8c18a70d",
        "Name": "Org2",
        "ParentId": "f035de7f",
        "Children": []
    }, {
        "Id": "b4514099",
        "Name": "Org3",
        "ParentId": "f035de7f",
        "Children": [{
            "Id": "8abe58d1",
            "Name": "Org4",
            "Children": []
        }],
    }, {
        "Id": "8e35bdc3",
        "Name": "Org5",
        "ParentId": "f035de7f",
        "Children": [{
            "Id": "331fffbf",
            "Name": "Org6",
            "ParentId": "8e35bdc3",
            "Children": [{
                "Id": "3bc3e085",
                "Name": "Org7",
                "ParentId": "331fffbf",
                "Children": []
            }],
        }],
    }],
}]



def flatten(data, prefix):
    if not data:
        return [prefix]

    result = []
    for org in data:
        name = org["Name"]
        result.extend(flatten(org["Children"], prefix + [name]))
    return result

print(flatten(data, []))
# [['Org1', 'Org2'], ['Org1', 'Org3', 'Org4'], ['Org1', 'Org5', 'Org6', 'Org7']]

同样,使用产量:

^{pr2}$

如果需要所有部分列表,则解决方案更短:

def flatten(data, prefix):
    yield prefix

    for org in data:
        name = org["Name"]
        yield from flatten(org["Children"], prefix + [name])

print(list(flatten(data, [])))
# [[], ['Org1'], ['Org1', 'Org2'], ['Org1', 'Org3'], ['Org1', 'Org3', 'Org4'], ['Org1', 'Org5'], ['Org1', 'Org5', 'Org6'], ['Org1', 'Org5', 'Org6', 'Org7']]

相关问题 更多 >