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

如何高效迭代生成无重复ID且ratio总和为1的字典数组组合

组合筛选性能优化方案

需求背景

需要从字典数组中筛选符合以下规则的所有组合:

  • 组合内不存在id重复的字典
  • 组合中所有字典的ratio值相加总和为1.0
  • 每个id对应的ratio取值范围为0.01到1.0,步长0.01

输入输出示例

输入数据源示例

_array_list = [
    {
        'id': 1,
        'ratio': .01
    },
    {
        'id': 1,
        'ratio': .02
    },
    # 省略同id其他ratio项
    {
        'id': 2,
        'ratio': .01
    },
    {
        'id': 3,
        'ratio': .02
    },
    # 省略其他id的ratio项
]

预期输出结构

results = [
    [
        {
            'id': 1,
            'ratio': .01
        },
        {
            'id': 2,
            'ratio': .99
        },
    ],
    [
        {
            'id': 1,
            'ratio': .50
        },
        {
            'id': 2,
            'ratio': .50
        },
    ],
    # 省略其他符合要求的组合
]

现有问题

原有实现采用全量组合遍历的逻辑,先枚举所有长度的组合,再判断id是否重复、总和是否为1.0,当存在5个不同ID、每个ID对应100个字典时,需要遍历约6亿次组合,耗时约20分钟,性能极差。

优化方案

核心思路

  1. 先按id对原始数组分组,每个id对应的所有ratio作为独立分组,组合时每个分组最多选1个元素,天然避免id重复的判断逻辑
  2. 将所有ratio乘以100转为整数计算,避免浮点数精度问题,求和目标转为100
  3. 采用回溯+剪枝的方式遍历分组,当前累加和超过100时直接停止该分支的遍历,砍掉绝大多数无效计算

优化后代码

from collections import defaultdict

def get_valid_combinations(_array_list):
    # 第一步:按id分组
    id_groups = defaultdict(list)
    for item in _array_list:
        # 转整数避免浮点误差,同时保留原字典引用
        ratio_int = int(round(item['ratio'] * 100))
        id_groups[item['id']].append((ratio_int, item))
    groups = list(id_groups.values())
    res = []
    
    # 回溯函数:当前处理的分组索引、当前累加和、当前已选的元素列表
    def backtrack(index, current_sum, path):
        if current_sum == 100:
            res.append(path.copy())
            return
        if current_sum > 100 or index >= len(groups):
            return
        # 分支1:不选当前分组的元素,直接处理下一个分组
        backtrack(index + 1, current_sum, path)
        # 分支2:选当前分组的一个元素
        for ratio_int, item in groups[index]:
            new_sum = current_sum + ratio_int
            if new_sum > 100:
                continue  # 剪枝,超过目标和直接跳过
            path.append(item)
            backtrack(index + 1, new_sum, path)
            path.pop()
    
    backtrack(0, 0, [])
    return res

# 调用方式
all_combos = get_valid_combinations(_array_list)

性能提升说明

针对5个id、每个id100个ratio的场景,优化后的实现状态数最多为id数量 * 目标和(100),仅为500个核心状态,加上剪枝逻辑,整体遍历次数不到10万次,运行耗时可从20分钟压缩到1秒以内。同时避免了浮点数求和的精度误差问题,结果准确性更高。


内容的提问来源于stack exchange,提问作者Bob Linux

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 08:39:03