【问题标题】:Printout specific keys and values in nested .json data recursively in python在python中递归打印嵌套.json数据中的特定键和值
【发布时间】:2021-10-23 19:59:57
【问题描述】:

所以我一直在反复尝试从复杂的嵌套 .json 文件中获取特定的值和键。

我发现一个好方法是使用递归函数。

我在基本层面等方面理解它。但我无法为我的原始文件创建一个。

import json

#open json file in folder
with open('demk-bkp-001.json') as file:
data = json.load(file)

这是完整的 .json 数据供参考:https://pastebin.com/hmjv81nS

我的目标是获取“name”、“size”和“mountpoint”中的每个值。

提示和示例在多个平台上似乎对我没有帮助,因此我找不到类似的嵌套 json 文件。请帮忙:)

【问题讨论】:

    标签: python json recursion nested


    【解决方案1】:

    迭代方法:将要处理的项目存储在数据结构中

    递归函数是一种可能性;另一种可能性是保留一个数据结构,其中包含您迄今为止遇到但尚未处理的所有字典;然后,只要您还有至少一本未处理的字典,就对其进行处理;如果它有孩子,请将它们添加到结构中。 这里我使用一个简单的python列表:

    names, sizes, mountpoints = [],[],[]
    to_be_processed = data['blockdevices']
    while to_be_processed:
      d = to_be_processed.pop()
      names.append(d['name'])
      sizes.append(d['size'])
      mountpoints.append(d['mountpoint'])
      if 'children' in d:
        to_be_processed.extend(d['children'])
    

    保留顺序:使用 FIFO 而不是 LIFO 数据结构

    请注意,上面提供的迭代代码使用 python 列表及其方法 .extend().pop()。实际上,这将 python 列表用作 LIFO,即后进先出数据结构。如果要保留数据的顺序,则需要使用 FIFO,即先进先出数据结构。您可以将.pop() 替换为.pop(0) 以删除第一个元素而不是最后一个元素,但请注意list.pop(0) 在python 中不是有效的操作;它需要从列表中复制所有元素。相反,我们可以使用 collections.deque 对象及其 .extend().popleft() 方法:

    import collections
    
    names, sizes, mountpoints = [],[],[]
    to_be_processed = collections.deque(data['blockdevices'])
    while to_be_processed:
      d = to_be_processed.popleft()
      names.append(d['name'])
      sizes.append(d['size'])
      mountpoints.append(d['mountpoint'])
      if 'children' in d:
        to_be_processed.extend(d['children'])
    

    递归方法

    递归方法也是可能的。在data['blockdevices'] 上调用它,并让它对孩子进行递归调用(如果有的话)。

    def process_data(d_list, names, sizes, mountpoints):
      for d in d_list:
        names.append(d['name'])
        sizes.append(d['size'])
        mountpoints.append(d['mountpoint'])
        if 'children' in d:
          process_data(d['children'], names, sizes, mountpoints)
      return names, sizes, mountpoints
    
    process_data(data['blockdevices'], [], [], [])
    

    【讨论】:

    • 非常感谢!从我的角度来看,这似乎是一个误解,我忘记了如何正确调用该功能!再次遇到麻烦时,我可以在这里问更多的东西吗?
    • @zed 那要看是什么麻烦了:)
    • 目前正在研究如何在某个条件下获取“名称”。我想找出其“大小”设置为 >5.0T 而没有另一个嵌套“孩子”的“名称”。在此示例中,它将是“name”:“sde”,因此它大于 5.0T,并且在“children”下没有另一个“children”。
    • 你好!我尝试将您向我展示的第一个函数(非递归函数)实现为打印出多个 .json 文件的 pandas 数据框,但键的顺序被奇怪地打印出来。递归的似乎工作正常,但我无法将它实现到我的数据帧代码中。 pastebin.com/CVbbgjya
    • @zed “奇怪的顺序”并不让我感到惊讶,而且应该相对容易修复。还记得我说过使用“数据结构”吗?对该数据结构的唯一要求是它具有向结构添加元素的功能,以及从结构中删除和读取元素的功能。我使用了带有方法.pop.extend 的python 列表。如果您阅读这些方法的文档,您会发现这实际上是将列表用作堆栈,即后进先出结构。不颠倒顺序读取数据,需要一个队列,即先进先出结构。
    【解决方案2】:

    您可以使用递归生成器执行以下操作:

    keys = ("name", "size", "mountpoint")
    
    def traverse(objs):
        for obj in objs:
            yield {k: obj[k] for k in keys}
            yield from traverse(obj.get("children", []))
    
    list(traverse(data["blockdevices"]))
    [{'mountpoint': None, 'name': 'sda', 'size': '931,5G'},
     {'mountpoint': None, 'name': 'sda1', 'size': '18,6G'},
     {'mountpoint': '/', 'name': 'md0', 'size': '18,6G'},
     {'mountpoint': None, 'name': 'sda2', 'size': '1K'},
     {'mountpoint': None, 'name': 'sda5', 'size': '9,3G'},
     {'mountpoint': '[SWAP]', 'name': 'md1', 'size': '9,3G'},
     {'mountpoint': None, 'name': 'sda6', 'size': '18,6G'},
     {'mountpoint': '/home', 'name': 'md2', 'size': '18,6G'},
     {'mountpoint': None, 'name': 'sda7', 'size': '885G'},
     {'mountpoint': '/var', 'name': 'md3', 'size': '884,8G'},
     {'mountpoint': None, 'name': 'sdb', 'size': '931,5G'},
     {'mountpoint': None, 'name': 'sdb1', 'size': '18,6G'},
     {'mountpoint': '/', 'name': 'md0', 'size': '18,6G'},
     {'mountpoint': None, 'name': 'sdb2', 'size': '1K'},
     {'mountpoint': None, 'name': 'sdb5', 'size': '9,3G'},
     {'mountpoint': '[SWAP]', 'name': 'md1', 'size': '9,3G'},
     {'mountpoint': None, 'name': 'sdb6', 'size': '18,6G'},
     {'mountpoint': '/home', 'name': 'md2', 'size': '18,6G'},
     {'mountpoint': None, 'name': 'sdb7', 'size': '885G'},
     {'mountpoint': '/var', 'name': 'md3', 'size': '884,8G'},
     {'mountpoint': None, 'name': 'sdc', 'size': '5,5T'},
     {'mountpoint': None, 'name': 'sdc1', 'size': '5,5T'},
     {'mountpoint': '/mnt/data', 'name': 'DATA', 'size': '5,5T'},
     {'mountpoint': None, 'name': 'sdd', 'size': '3,7T'},
     {'mountpoint': None, 'name': 'sdd1', 'size': '3,7T'},
     {'mountpoint': '/mnt/data2', 'name': 'DATA2', 'size': '3,7T'},
     {'mountpoint': None, 'name': 'sde', 'size': '9,1T'},
     {'mountpoint': None, 'name': 'sde1', 'size': '9,1T'}]
    

    【讨论】:

    • 如何打印出新制作的列表以便在终端中查看?
    猜你喜欢
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    • 2020-11-25
    • 2013-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    相关资源
    最近更新 更多