根据条件Python

时间:2017-07-09 15:13:49

标签: python json loops

我正在开发Adobe Analytics报告/数据仓库API,以及如何将这些数据处理成行和列(我使用python和pandas来解决这个问题)。只要只使用一个维度,这一切都很顺利,但是当查询多个维度时,故障的想法就会发挥作用。

例如,当我使用2维时,数据(JSON格式)看起来像这样:

{
    "report":{
        "data":[
            {
                "name":"June 13,2017",
                "breakdown":[
                    {
                        "name":"nl",
                        "breakdown":[
                            {
                                "name":"not logged in",
                                "counts":[
                                    "10",
                                    "12"
                                ]
                            },
                            {
                                "name":"logged in",
                                "counts":[
                                    "30",
                                    "2"
                                ]
                            }
                        ]
                    }, ... etc.

详细说明,count代表一系列指标,每个细分代表一个维度(数字和名称都是虚构的)。

我想在这里做的是建立我最终可以按行和列链接在一​​起的数据集,因此示例的第一行将是(" 6月13,2017",& #34; nl","未登录",10,12)。

在示例情况下,我已经可以使用以下代码执行此操作:

for period in dataObj['report']['data']: 
    for firstbreakdown in period['breakdown']:
        for secondbreakdown in firstbreakdown['breakdown']:
            print(period['name'], firstbreakdown['name'], secondbreakdown['name'], secondbreakdown['counts'])

在这里处理计数并不是问题,因为我发现我可以轻松地用熊猫做到这一点。但是这里有棘手的部分和我的实际问题:JSON示例中的故障数量取决于查询的维度数。

如何根据查询的维度数量自动生成足够的循环,以便连续获取所有维度值和计数?

我更喜欢优雅和优雅的总是工作的解决方案,而不是if else语句。

1 个答案:

答案 0 :(得分:1)

递归方法

如果你不介意递归(见下文),解决这个问题的一种方法是使用递归函数来迭代越来越深的维度。例如:

def iterBD(dim, breakdown):
  if (dim > 0):
    return [ [breakdown["name"]] + iterBD(dim - 1, sub) for sub in breakdown["breakdown"] ]
  return [ [breakdown["name"]] + data["counts"] for data in breakdown ]

然后使用例如调用您的示例数据iterBD(2, report.data)。结果将是格式列表:

["June 13,2017", "nl", "not logged in", ["10", "12"]]
["June 13,2017", "nl", "logged in", ["30", "2"]]
...

如果要处理具有不同维数的异构数据/行,则可能会检测是否存在要迭代的其他维。例如:

def iterBD2(breakdown):
  if (hasattr(breakdown, "breakdown")):
    return [ [breakdown["name"]] + iterBD2(sub) for sub in breakdown["breakdown"] ]
  return [ [breakdown["name"]] + data["counts"] for data in breakdown ]

(可能想要hasattr / try ... catch / {/ p>}查看此How to know if an object has an attribute in Python

此方法将被称为iterBD2(report.data),而无需指定尺寸。

递归时可能不好

以上是一种递归方法,这意味着它依赖于维度相对较少的数据。如果有一行例如成千上万的嵌套维度,Python可能有堆栈问题。与任何递归函数一样,上述内容可以重写为非递归函数。正如您在评论中指出的那样,在特定情况下维度的数量永远不会那么高,如果您必须处理这样的问题,可能是时候重新考虑查询本身以获得更好的数据了。