【问题标题】:determine number of loops based on condition Python根据条件 Python 确定循环数
【发布时间】:2017-12-13 08:29:04
【问题描述】:

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

例如,当我使用二维时,数据(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.

详细来说,计数代表一组指标,每个细分代表一个维度(数字和名称是虚构的)。

我想要在这里做的是建立我最终可以在行和列中链接在一起的数据集,因此示例的第一行将是 ("June 13,2017","nl","not登录",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'])

在这里处理计数不是问题,因为我发现我可以很容易地用 pandas 做到这一点。但棘手的部分和我的实际问题出现了:JSON 示例中的细分数量由查询的维度数量决定。

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

我更喜欢优雅且始终有效的解决方案,而不是 if else 语句。

【问题讨论】:

  • 你想避免递归吗? IE。维度的数量是否会变得非常重要,比如数百甚至更多?
  • 是的,递归是我想到的第一个想法——这个答案可以提供灵感:stackoverflow.com/questions/21028979/…
  • 我认为这不是问题,因为帐户中实际上不超过 100-150 个维度,而且您永远不会在一份报告中使用所有维度

标签: python json loops


【解决方案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 ]

(可能想检查这个How to know if an object has an attribute in Python 是否有hasattr / 使用try ... catch

这个方法的调用类似于iterBD2(report.data),而无需指定维度。


当递归可能不好时

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

【讨论】:

    猜你喜欢
    • 2022-06-22
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 2018-01-05
    • 2020-01-06
    • 1970-01-01
    • 2015-10-03
    • 1970-01-01
    相关资源
    最近更新 更多