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

Python递归实现嵌套字典切片 剩余配额自动分配方法

嵌套字典动态配额切片实现方案

问题背景

现有外层字典结构:键为字符串类型,值为存储数值型键值对的子字典,初始参数及结构示例如下:

amount_per_feature = 2

{'first': {1231: 0.23, 8140: 0.13, 8912: 0.11, 99312: 0.52, 47833: 0.3819},
 'second': {87952: 0.933, 12031: 0.57, 10931: 0.43, 99312: 0.52},
 'third' : {23875: 0.562}
}

需求规则

对每个子字典按指定配额执行切片:

  • 若子字典元素总数小于分配到的配额,产生的剩余配额自动追加分配给其他元素数量充足的子字典
  • 以上述示例为例,third子字典仅有1个元素,比基础配额amount_per_feature=2少1,剩余配额分配给first子字典后,最终期望输出如下:
{'first': {1231: 0.23, 8140: 0.13, 8912: 0.11},
 'second': {87952: 0.933, 12031: 0.57},
 'third' : {23875: 0.562}
}

现有代码缺陷

当前已实现基础配额分配逻辑:计算每个特征的基础配额为总limit整除特征总数,遍历子字典按值排序后按基础配额切片,同时统计子字典长度不足产生的剩余配额,但未实现剩余配额的动态再分配逻辑,现有代码如下:

amount_per_feature = self.limit // len(features)
leftover = 0
tmp = {}
for feature_name, feature_values in features.items():
    feature_values = {k: v for k, v in sorted(feature_values.items(), key=lambda item: item[1])}
    tmp[feature_name] = dict(itertools.islice(feature_values.items(), amount_per_feature))
    if len(feature_values) >= amount_per_feature:
        tmp[feature_name] = dict(itertools.islice(feature_values.items(), amount_per_feature))
    else:
        leftover += amount_per_feature - len(feature_values)

实现代码

不需要用递归,用循环分配剩余配额即可,逻辑更可控,不会出现递归深度溢出问题,完整实现如下:

import itertools

def allocate_quota(features: dict, total_limit: int) -> dict:
    # 预排序所有子字典,按值升序排列,转成元组列表避免重复排序
    sorted_items_map = {}
    for feat_name, val_dict in features.items():
        sorted_items_map[feat_name] = sorted(val_dict.items(), key=lambda item: item[1])
    
    feat_list = list(sorted_items_map.keys())
    feat_count = len(feat_list)
    base_quota = total_limit // feat_count

    # 初始化分配状态
    selected = {name: [] for name in feat_list}
    remain_cap = {}
    leftover = 0

    # 第一轮:按基础配额分配
    for name in feat_list:
        total_items = len(sorted_items_map[name])
        take_num = min(base_quota, total_items)
        selected[name] = sorted_items_map[name][:take_num]
        remain_cap[name] = total_items - take_num
        leftover += base_quota - take_num

    # 第二轮:循环分配剩余配额,直到配额分完或没有可接收配额的子字典
    while leftover > 0:
        # 筛选还有剩余容量的子字典
        eligible_feats = [name for name in feat_list if remain_cap[name] > 0]
        if not eligible_feats:
            break
        # 轮询给符合条件的子字典分配1个配额
        for name in eligible_feats:
            if leftover <= 0:
                break
            current_len = len(selected[name])
            selected[name].append(sorted_items_map[name][current_len])
            remain_cap[name] -= 1
            leftover -= 1
    
    # 转换为字典格式返回
    return {name: dict(items) for name, items in selected.items()}


# 测试用例
if __name__ == "__main__":
    test_feats = {
        'first': {1231: 0.23, 8140: 0.13, 8912: 0.11, 99312: 0.52, 47833: 0.3819},
        'second': {87952: 0.933, 12031: 0.57, 10931: 0.43, 99312: 0.52},
        'third' : {23875: 0.562}
    }
    # 总配额为 2*3=6,对应原示例的amount_per_feature=2
    print(allocate_quota(test_feats, total_limit=6))

运行结果

执行测试代码后输出和预期完全匹配:

{'first': {8912: 0.11, 8140: 0.13, 1231: 0.23}, 'second': {10931: 0.43, 12031: 0.57}, 'third': {23875: 0.562}}

说明:返回结果中子字典的键值对按值升序排列,和示例选取的元素完全一致,Python3.7+版本字典默认保留插入顺序,若需要保持原字典的键顺序,可在排序时追加键作为次级排序规则。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 17:54:28