在 Python 中通过嵌套的 Json/dict 解析

Posted

技术标签:

【中文标题】在 Python 中通过嵌套的 Json/dict 解析【英文标题】:Parsing through Nested Json/dict in Python 【发布时间】: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"
        
    ]

【问题讨论】:

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

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

你应该得到这样的结果:

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

【讨论】:

非常酷和整洁,非常喜欢。关于如何忽略第一个值的任何提示? 查看这篇文章:How to remove the first item in a list【参考方案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开始)

【讨论】:

以上是关于在 Python 中通过嵌套的 Json/dict 解析的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Mysql 中通过 LIKE 使用嵌套的 SELECT?

如何使用存储库接口在 Spring Data 中通过其嵌套对象的 objectId 查找集合?

如何在 VUE 中通过 v-model 直接更新嵌套对象数组值?

为啥我的添加好友测试路由在 insomina 中通过了 200 OK,但是当我调用获取所有用户时它没有嵌套?

在 Java 中通过 XSLT 进行 XML 粉碎

python 处理json,list to dict