【问题标题】:Python group by multiple keys in a dict [closed]Python按字典中的多个键分组[关闭]
【发布时间】:2021-09-30 15:44:32
【问题描述】:

我有一个要按多个键分组的字典列表。

我在python dict中默认使用了排序

data = [
[],
[{'value': 8, 'bot': 'DB', 'month': 9, 'year': 2020}, {'value': 79, 'bot': 'DB', 'month': 10, 'year': 2020}, {'value': 126, 'bot': 'DB', 'month':8, 'year': 2021}],
[],
[{'value': 222, 'bot': 'GEMBOT', 'month': 11, 'year': 2020}, {'value': 623, 'bot': 'GEMBOT', 'month': 4, 'year': 2021}, {'value': 628, 'bot': 'GEMBOT', 'month': 9, 'year': 2021}],
[{'value': 0, 'bot': 'GEMBOT', 'month': 4, 'year': 2021}],
[{'value': 703, 'bot': 'DB', 'month': 11, 'year': 2020}, {'value': 1081, 'bot': 'DB', 'month': 3, 'year': 2021}, {'value': 1335, 'bot': 'DB', 'month': 10, 'year': 2020}, {'value': 1920, 'bot': 'DB', 'month': 4, 'year': 2021}, {'value': 2132, 'bot': 'DB', 'month': 1, 'year': 2021}, {'value': 2383, 'bot': 'DB', 'month': 2, 'year': 2021}]
]

output_dict = {}

for i in data:
    if not i:
        pass
    for j in i:
        for key,val in sorted(j.items()):
            output_dict.setdefault(val, []).append(key)

            
print(output_dict)
    
{'DB': ['bot', 'bot', 'bot', 'bot', 'bot', 'bot', 'bot', 'bot', 'bot'], 9: ['month', 'month', 'month'], 8: ['value'], 2020: ['year', 'year', 'year', 'year', 'year'], 10: ['month', 'month'], 79: ['value'], 126: ['value'], 2021: ['year', 'year', 'year', 'year', 'year', 'year', 'year', 'year'], 'GEMBOT': ['bot', 'bot', 'bot', 'bot'], 11: ['month', 'month'], 222: ['value'], 4: ['month', 'month', 'month'], 623: ['value'], 628: ['value'], 0: ['value'], 703: ['value'], 3: ['month'], 1081: ['value'], 1335: ['value'], 1920: ['value'], 1: ['month'], 2132: ['value'], 2: ['month'], 2383: ['value']}

但我想要这样的输出。

[{ "bot": "DB",
   "date": "Sept 20",
   "value": 134
},{"bot": "DB",
   "date": "Oct 20",
   "value": 79
}.. So on ]

有没有一种有效的方法来扁平化这个列表?

提前致谢

【问题讨论】:

  • 输入中没有日期字段
  • 签出pdb - The Python Debugger 来调试小程序python3 -m pdb myscript.py .. 使用b 设置断点(这样你就可以在那里检查你的程序),c 运行到那个点(继续)和? 探索命令.. 这将允许您检查程序的实时状态,无论您是断点还是继续
  • 是的没有日期输入只有月份,根据月份和年份获取日期。 @DaniMesejo
  • 也许你可以写一个更好的例子来说明你想要什么
  • 从 2 天以来,我一直在努力解决这个问题。这正是我的用例@DaniMesejo

标签: python python-3.x dictionary


【解决方案1】:

有两件事会让这个问题更容易回答。第一个是列表推导,它将提升子项:

data_reshaped = [cell for row in data for cell in row]

这将把你原来的data 压扁一点:

[
    {'value': 8, 'bot': 'DB', 'month': 9, 'year': 2020},
    {'value': 79, 'bot': 'DB', 'month': 10, 'year': 2020},
    {'value': 126, 'bot': 'DB', 'month': 8, 'year': 2021},
    {'value': 222, 'bot': 'GEMBOT', 'month': 11, 'year': 2020},
    {'value': 623, 'bot': 'GEMBOT', 'month': 4, 'year': 2021},
    {'value': 628, 'bot': 'GEMBOT', 'month': 9, 'year': 2021},
    {'value': 0, 'bot': 'GEMBOT', 'month': 4, 'year': 2021},
    {'value': 703, 'bot': 'DB', 'month': 11, 'year': 2020},
    {'value': 1081, 'bot': 'DB', 'month': 3, 'year': 2021},
    {'value': 1335, 'bot': 'DB', 'month': 10, 'year': 2020},
    {'value': 1920, 'bot': 'DB', 'month': 4, 'year': 2021},
    {'value': 2132, 'bot': 'DB', 'month': 1, 'year': 2021},
    {'value': 2383, 'bot': 'DB', 'month': 2, 'year': 2021}
]

现在我们可以使用复合键和setdefault() 对其进行迭代以聚合结果。请注意,如果您更愿意像我一样使用collections.defaultdict(),那么请将其换成setdefault()

results = {}
for cell in data_reshaped:
    key = f"{cell['bot']}_{cell['year']}_{cell['month']}"
    value = cell["value"] # save the value so we can reset cell next
    cell["value"] = 0 # setting this to 0 cleans up the next line.
    results.setdefault(key, cell)["value"] += value

这应该允许您:

for result in results.values():
    print(result)

给予:

{'value': 8, 'bot': 'DB', 'month': 9, 'year': 2020}
{'value': 1414, 'bot': 'DB', 'month': 10, 'year': 2020}
{'value': 126, 'bot': 'DB', 'month': 8, 'year': 2021}
{'value': 222, 'bot': 'GEMBOT', 'month': 11, 'year': 2020}
{'value': 623, 'bot': 'GEMBOT', 'month': 4, 'year': 2021}
{'value': 628, 'bot': 'GEMBOT', 'month': 9, 'year': 2021}
{'value': 703, 'bot': 'DB', 'month': 11, 'year': 2020}
{'value': 1081, 'bot': 'DB', 'month': 3, 'year': 2021}
{'value': 1920, 'bot': 'DB', 'month': 4, 'year': 2021}
{'value': 2132, 'bot': 'DB', 'month': 1, 'year': 2021}
{'value': 2383, 'bot': 'DB', 'month': 2, 'year': 2021}

完整解决方案:

data = [
    [],
    [
        {'value': 8, 'bot': 'DB', 'month': 9, 'year': 2020},
        {'value': 79, 'bot': 'DB', 'month': 10, 'year': 2020},
        {'value': 126, 'bot': 'DB', 'month':8, 'year': 2021}
    ],
    [],
    [
        {'value': 222, 'bot': 'GEMBOT', 'month': 11, 'year': 2020},
        {'value': 623, 'bot': 'GEMBOT', 'month': 4, 'year': 2021},
        {'value': 628, 'bot': 'GEMBOT', 'month': 9, 'year': 2021}
    ],
    [
        {'value': 0, 'bot': 'GEMBOT', 'month': 4, 'year': 2021}
    ],
    [
        {'value': 703, 'bot': 'DB', 'month': 11, 'year': 2020},
        {'value': 1081, 'bot': 'DB', 'month': 3, 'year': 2021},
        {'value': 1335, 'bot': 'DB', 'month': 10, 'year': 2020},
        {'value': 1920, 'bot': 'DB', 'month': 4, 'year': 2021},
        {'value': 2132, 'bot': 'DB', 'month': 1, 'year': 2021},
        {'value': 2383, 'bot': 'DB', 'month': 2, 'year': 2021}
    ]
]

data_reshaped = [cell for row in data for cell in row]

results = {}
for cell in data_reshaped:
    key = f"{cell['bot']}_{cell['year']}_{cell['month']}"
    value = cell["value"]
    cell["value"] = 0
    results.setdefault(key, cell)["value"] += value

for result in results.values():
    print(result)

再次给予:

{'value': 8, 'bot': 'DB', 'month': 9, 'year': 2020}
{'value': 1414, 'bot': 'DB', 'month': 10, 'year': 2020}
{'value': 126, 'bot': 'DB', 'month': 8, 'year': 2021}
{'value': 222, 'bot': 'GEMBOT', 'month': 11, 'year': 2020}
{'value': 623, 'bot': 'GEMBOT', 'month': 4, 'year': 2021}
{'value': 628, 'bot': 'GEMBOT', 'month': 9, 'year': 2021}
{'value': 703, 'bot': 'DB', 'month': 11, 'year': 2020}
{'value': 1081, 'bot': 'DB', 'month': 3, 'year': 2021}
{'value': 1920, 'bot': 'DB', 'month': 4, 'year': 2021}
{'value': 2132, 'bot': 'DB', 'month': 1, 'year': 2021}
{'value': 2383, 'bot': 'DB', 'month': 2, 'year': 2021}

我将由您来决定将两个日期字段转换为其他演示文稿,因为这似乎与手头的问题不符。

【讨论】:

    【解决方案2】:

    不妨试试:

    from pprint import pprint
    import datetime
    
    output_dict = []
    
    for i in data:
      if i:
        for j in i:
          for key, val in sorted(j.items()):
            if key == "bot":
              temp["bot"] = val
            elif key == "value":
              temp["value"] = val
            elif key == "month":
              month = datetime.datetime.strptime(str(val), "%m")
              temp["date"] = month.strftime("%b")
            elif key == "year":
              temp["date"] = str(temp["date"]) + " " + str(val)
          output_dict.append(temp)
          temp = {}
    
    pprint(output_dict)
    

    最终结果如下:

    [{'bot': 'DB', 'date': 'Sep 2020', 'value': 8},
     {'bot': 'DB', 'date': 'Oct 2020', 'value': 79},
     {'bot': 'DB', 'date': 'Aug 2021', 'value': 126},
     {'bot': 'GEMBOT', 'date': 'Nov 2020', 'value': 222},
     {'bot': 'GEMBOT', 'date': 'Apr 2021', 'value': 623},
     {'bot': 'GEMBOT', 'date': 'Sep 2021', 'value': 628},
     {'bot': 'GEMBOT', 'date': 'Apr 2021', 'value': 0},
     {'bot': 'DB', 'date': 'Nov 2020', 'value': 703},
     {'bot': 'DB', 'date': 'Mar 2021', 'value': 1081},
     {'bot': 'DB', 'date': 'Oct 2020', 'value': 1335},
     {'bot': 'DB', 'date': 'Apr 2021', 'value': 1920},
     {'bot': 'DB', 'date': 'Jan 2021', 'value': 2132},
     {'bot': 'DB', 'date': 'Feb 2021', 'value': 2383}]
    

    【讨论】:

    • 谢谢你的作品
    • @user9538877 如果你想要一个单独的{'bot': 'DB', 'date': '10 2020', 'value': 1414},它就行不通了
    【解决方案3】:

    不妨试试:

    output = []
    for i in data:
        if not i:
            pass
        for j in i:
            output.append(j)
    

    然后,如果您想对其进行排序,则可以使用sorted_output = sorted(ouput, key=lambda k: k['bot']) 对其进行排序,例如bot。如果您想按日期对其进行排序,可以创建一个以月为单位计算日期的值,然后从那里对其进行排序。

    【讨论】:

    • 有趣的想法让我看看
    • 您可以通过以下方式添加以月为单位的日期:sorted_output = sorted(ouput, key=lambda k: k['year']*12 + k['month']) 或者干脆不以月和年为单位存储日期,而是以年为单位存储,然后分别计算年数。
    猜你喜欢
    • 1970-01-01
    • 2016-10-09
    • 2020-04-16
    • 1970-01-01
    • 2021-03-13
    • 1970-01-01
    • 2017-02-24
    • 2014-10-26
    • 2014-01-02
    相关资源
    最近更新 更多