You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python按filter分组求和proportion,寻求更优Pythonic实现方案

按filter分组求和的Python优化方案

输入数据

presets = [{'proportion': 1, 'filter': {'tagger_mood': ['sad', 'party']}},
{'proportion': 1, 'filter': {'vocal_instrumental': 1}},
{'proportion': 1, 'filter': {'vocal_instrumental': 2}},
{'proportion': 1.1, 'filter': {'tagger_mood': ['sad', 'party']}},
{'proportion': 1.1, 'filter': {'vocal_instrumental': 1}},
{'proportion': 1.1, 'filter': {'vocal_instrumental': 2}}]

需求

按filter字段分组,对每组的proportion求和,最终得到如下结构的结果:

[
    {'proportion': 2.1, 'filter': {'tagger_mood': ['sad', 'party']}},
    {'proportion': 2.1, 'filter': {'vocal_instrumental': 1}},
    {'proportion': 2.1, 'filter': {'vocal_instrumental': 2}}
]

原实现代码

presets = [...]
merged_filter = []
merged_proportion = []
for preset in presets:
    if preset['filter'] not in merged_filter:
        merged_filter.append(preset['filter'])
        merged_proportion.append(preset['proportion'])
    else:
        merged_proportion[merged_filter.index(preset['filter'])] += preset['proportion']
print([{'proportion': p, 'filter': f} for p, f in zip(merged_proportion, merged_filter)])

优化方案

原实现的时间复杂度为O(n²),因为每次判断preset['filter'] not in merged_filter和调用merged_filter.index()都需要遍历列表。以下是几种更高效、符合Python风格的实现方式:

方案1:使用collections.defaultdict(最优效率)

由于字典无法直接作为字典的键,我们先将filter字典转换为可哈希的tuple(对键值对排序避免顺序影响),再用defaultdict累加求和:

from collections import defaultdict

sum_dict = defaultdict(float)

for item in presets:
    # 将filter转为可哈希的键
    filter_key = tuple(sorted(item['filter'].items()))
    sum_dict[filter_key] += item['proportion']

# 转换为目标格式
result = [{'proportion': val, 'filter': dict(key)} for key, val in sum_dict.items()]
print(result)

该方案时间复杂度为O(n),效率远高于原实现,逻辑清晰易读。

方案2:使用itertools.groupby(简洁风格)

groupby需要先按分组键排序,适合数据量不大的场景:

from itertools import groupby

# 定义分组键的转换函数
def get_filter_key(item):
    return tuple(sorted(item['filter'].items()))

# 先按分组键排序
presets_sorted = sorted(presets, key=get_filter_key)

# 分组求和
result = []
for key, group in groupby(presets_sorted, key=get_filter_key):
    total_proportion = sum(item['proportion'] for item in group)
    result.append({'proportion': total_proportion, 'filter': dict(key)})

print(result)

该方案代码简洁,但排序带来O(n log n)的时间复杂度,适合对性能要求不极致的场景。

方案3:使用普通字典(无额外依赖)

如果不想导入模块,可直接用普通字典实现,逻辑与defaultdict一致:

sum_dict = {}

for item in presets:
    filter_key = tuple(sorted(item['filter'].items()))
    if filter_key in sum_dict:
        sum_dict[filter_key] += item['proportion']
    else:
        sum_dict[filter_key] = item['proportion']

result = [{'proportion': val, 'filter': dict(key)} for key, val in sum_dict.items()]
print(result)

该方案无需依赖任何模块,同样实现O(n)的时间复杂度,简洁高效。

内容的提问来源于stack exchange,提问作者Andrey Ivanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:07:04