【问题标题】:Parsing through Nested Json/dict in Python在 Python 中通过嵌套的 Json/dict 解析
【发布时间】:2021-05-15 20:00:05
【问题描述】:

处理一些讨厌的 JSON。我正在使用 json.load 写入文件并将其存储为 dict 类型,打印在下面。在 python 中,我将如何获取仅在“false_value”之后开始的“维度”值的列表(因为它们的第一个维度值实际上不是我想要的值)。

我尝试了一种 hacky 方式,但感觉有人可能对如何以更有说服力的方式做到这一点有看法。

目标,列出所有维度值(除第一个之外),例如 ('100', '121' ...)

{
    "reports": [
        {
            "columnHeader": {
                "dimensions": [
                    "ga:clientId"
                ],
                "metricHeader": {
                    "metricHeaderEntries": [
                        {
                            "name": "blah",
                            "type": "INTEGER"
                        }
                    ]
                }
            },
            "data": {
                "rows": [
                    {
                        "dimensions": [
                            "false_value"
                        ],
                        "metrics": [
                            {
                                "values": [
                                    "2"
                                ]
                            }
                        ]
                    },
    {
                        "dimensions": [
                            "100"
                        ],
                        "metrics": [
                            {
                                "values": [
                                    "2"
                                ]
                            }
                        ]
                    },
                    {
                        "dimensions": [
                            "121"
                        ],
                        "metrics": [
                            {
                                "values": [
                                    "1"
                                ]
                            }
                        ]
                    },
                    {
                        "dimensions": [
                            "1212"
                        ],
                        "metrics": [
                            {
                                "values": [
                                    "1"
                                ]
                            }
                        ]
                    }, ],
                "totals": [
                    {
                        "values": [
                            "10497"
                        ]
                    }
                ],
                "rowCount": 9028,
                "minimums": [
                    {
                        "values": [
                            "0"
                        ]
                    }
                ],
                "maximums": [
                    {
                        "values": [
                            "9"
                        ]
                    }
                ],
                "isDataGolden": true
            },
            "nextPageToken": "1000"
        }
    ]
}

【问题讨论】:

  • 我相信您可以遍历所有键/子键/值并将它们转储到列表中。见这里:stackoverflow.com/questions/45974937
  • 您的意思是 True 而不是 true(即 Python Boolean 的 True/False)?
  • @DarrylG 这是 JSON,不是 Python 代码。
  • 一个在条件中使用isinstance() 的简单递归函数应该可以解决问题。
  • @DannyVarod--当 OP 说“它存储的是 dict 类型,打印在下面”时,我假设 OP 显示为字典。如果我们将其视为字符串,那么 json.loads(...) 会给出结构错误(这也是由字符串的 json lint 验证器引发的)。如果将 true 更改为 True,则它可以作为字典使用。

标签: python dictionary


【解决方案1】:

首先,你应该把你的 json 对象放在一个更好的文本可读形式。使用Black 之类的东西来清理空间。 然后只需遍历键,直到找到所需的值,此 post 将帮助您。

你应该得到这样的结果:

dimensions = [row["dimensions"][0] for row in json["reports"][0]["data"]["rows"]]

【讨论】:

【解决方案2】:

使用递归函数查找具有两个条件的值

  • 父键是维度
  • 只取数值

代码

def find_dims(d, inside = False, results = None):
    '''
        Recursive processing of structure
        inside  = True when parent was "dimensions"
    '''
    if results is None:
        results = []
        
    if isinstance(d, dict):
        for k, v in d.items():
            find_dims(v, k=="dimensions" or inside, results)
    elif isinstance(d, list):
        for k in d:
            find_dims(k, inside, results)
    else:
        if inside and d.isdigit():
            # inside dimensions with a number
            results.append(int(d))
            
    return results

测试

OP 字典(将 true 更改为 True)

d = {
    "reports": [
        {
            "columnHeader": {
                "dimensions": [
                    "ga:clientId"
                ],
                "metricHeader": {
                    "metricHeaderEntries": [
                        {
                            "name": "blah",
                            "type": "INTEGER"
                        }
                    ]
                }
            },
            "data": {
                "rows": [
                    {
                        "dimensions": [
                            "false_value"
                        ],
                        "metrics": [
                            {
                                "values": [
                                    "2"
                                ]
                            }
                        ]
                    },
    {
                        "dimensions": [
                            "100"
                        ],
                        "metrics": [
                            {
                                "values": [
                                    "2"
                                ]
                            }
                        ]
                    },
                    {
                        "dimensions": [
                            "121"
                        ],
                        "metrics": [
                            {
                                "values": [
                                    "1"
                                ]
                            }
                        ]
                    },
                    {
                        "dimensions": [
                            "1212"
                        ],
                        "metrics": [
                            {
                                "values": [
                                    "1"
                                ]
                            }
                        ]
                    }, ],
                "totals": [
                    {
                        "values": [
                            "10497"
                        ]
                    }
                ],
                "rowCount": 9028,
                "minimums": [
                    {
                        "values": [
                            "0"
                        ]
                    }
                ],
                "maximums": [
                    {
                        "values": [
                            "9"
                        ]
                    }
                ],
                "isDataGolden": True
            },
            "nextPageToken": "1000"
        }
    ]
}

print(find_dims(d)) # Output: [100, 121, 1212]

【讨论】:

    【解决方案3】:

    就像 cmets 中所说的,你可以只使用一个简单的递归函数,例如:

    all_dimensions = []
    search_key = 'dimensions'
    def searchDimensions(data):
        if isinstance(data, dict):
            for (key, sub_data) in data.items():
                if key == search_key: all_dimensions.extend(sub_data)
                else: all_dimensions.extend(searchDimensions(sub_data))
    
        elif isinstance(data, list):
            for sub_data in data:
                all_dimensions.extend(searchDimensions(sub_data))
    
        return []
    
    searchDimensions(example)
    false_value_index = all_dimensions.index('false_value') + 1
    output = all_dimensions[false_value_index:]
    print(output)
    >>> ['100', '121', '1212']
    

    然后过滤你不想要的值(例如,从false_value开始)

    【讨论】:

      猜你喜欢
      • 2018-09-12
      • 1970-01-01
      • 1970-01-01
      • 2021-06-30
      • 1970-01-01
      • 2022-11-15
      • 2020-10-09
      • 2021-06-18
      • 1970-01-01
      相关资源
      最近更新 更多