如何高效合并含相同month时间戳的多字典列表?
问题
我有一个包含100余个字典的列表,每个字典包含month(datetime类型)及各类状态统计值,示例数据如下:
[ {'month': datetime.datetime(2022, 4, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 1, 'Open': 0, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 1, 'Open': 0, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 1, 'Open': 0, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 6, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 7, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0} ]
需求:将所有字典按相同month时间戳合并,每个时间戳仅保留一个字典,对应统计值求和,预期输出如下:
[ {'month': datetime.datetime(2022, 4, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 1, 'Open': 0, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 4, 'Win': 0, 'Loss': 2, 'Open': 2, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 6, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 7, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0} ]
我之前尝试循环比对前一个对象的方法,耗时过长,请问最高效的实现方式是什么?
高效实现方案
方法1:原生Python字典分组(O(n)时间复杂度,最优解)
利用字典键查找O(1)的特性,以month为键分组,仅遍历一次列表即可完成统计,是当前数据量下的最快方案:
import datetime import zoneinfo def merge_monthly_data(data): grouped = {} for item in data: month_key = item['month'] if month_key in grouped: # 累加所有统计字段 for key in ['total', 'Win', 'Loss', 'Open', 'Dormant', 'Pending', 'Cancelled']: grouped[month_key][key] += item[key] else: # 首次出现该月份,复制条目到分组字典 grouped[month_key] = item.copy() # 转换为列表,如需按时间排序可追加sorted逻辑 return list(grouped.values()) # 测试示例数据 sample_data = [ {'month': datetime.datetime(2022, 4, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 1, 'Open': 0, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 1, 'Open': 0, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 1, 'Open': 0, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 6, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}, {'month': datetime.datetime(2022, 7, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0} ] result = merge_monthly_data(sample_data) for item in result: print(item)
说明:datetime对象是可哈希类型,可直接作为字典键。该方法时间复杂度为O(n),远优于循环比对的O(n²)方案。如需结果按时间排序,可将返回语句改为:
return sorted(grouped.values(), key=lambda x: x['month'])
方法2:使用Pandas(适合复杂统计场景)
如果后续需要更多数据处理操作,Pandas的分组聚合功能代码更简洁,性能对于100+数据量完全够用:
import pandas as pd import datetime import zoneinfo sample_data = [ # 同上示例数据 ] # 转换为DataFrame df = pd.DataFrame(sample_data) # 按month分组并求和统计字段 merged_df = df.groupby('month').sum().reset_index() # 转换回字典列表 result = merged_df.to_dict('records') print(result)
说明:Pandas内部优化了分组逻辑,无需手动遍历累加,适合需要后续数据分析的场景。
内容的提问来源于stack exchange,提问作者ChicagoMG2022
相关产品推荐
相关产品推荐

