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

嵌套字典迭代报错:构建双向通话时长字典求助

解决字典迭代时修改大小引发的RuntimeError问题

问题描述

现有嵌套字典,外层键为主叫手机号,内层键为被叫手机号,值为通话时长(秒)。需要将其转换为双向完整通话字典:所有出现的号码作为外层键,对应内层键为通话对象,值为累计通话时长,已有记录则累加时长。尝试的代码触发了RuntimeError: dictionary changed size during iteration,需提供可行实现方法。

原始字典

call_dict = {
    '123456789': {'132456789': 583, '123546789': 444, '257918896': 528, '111111111': 495},
    '296358741': {'132456789': 631, '123456789': 98, '456789123': 395},
    111111111: {'123456789': 150}
}

注:避免使用dict作为变量名,这会覆盖Python内置的dict类型

期望结果

result_dict = {
    '123456789': {'132456789': 583, '123546789': 444, '257918896': 528, '111111111': 645, '296358741': 98},
    '296358741': {'132456789': 631, '123456789': 98, '456789123': 395},
    '132456789': {'123456789': 583, '296358741': 631},
    '111111111': {'123456789': 645},
    '456789123': {'296358741': 395},
    '123546789': {'123456789': 444},
    '257918896': {'123456789': 528}
}

注:将495+150替换为实际累加结果645,同时去除了重复的'296358741'键

错误原因分析

原代码直接迭代原字典for k in dict,在迭代过程中通过dict[called] = ...给字典添加新键,这会改变字典的大小。Python中字典在迭代时不允许修改其结构(增删键),因此触发RuntimeError: dictionary changed size during iteration。

可行解决方案

方案1:迭代原字典键的副本

通过list(dict.keys())获取原字典所有键的列表副本,迭代这个固定的列表,即使原字典后续新增键,也不会影响迭代过程。

修改后的代码:

# 重命名变量避免覆盖内置dict
call_dict = {
    '123456789': {'132456789': 583, '123546789': 444, '257918896': 528, '111111111': 495},
    '296358741': {'132456789': 631, '123456789': 98, '456789123': 395},
    111111111: {'123456789': 150}
}

# 迭代键的列表副本
for caller in list(call_dict.keys()):
    # 统一键的类型为字符串,避免数字和字符串键重复(比如111111111和'111111111')
    caller_str = str(caller)
    # 确保主叫号码在字典中是字符串键
    if caller != caller_str:
        call_dict[caller_str] = call_dict.pop(caller)
        caller = caller_str
    
    called_dict = call_dict[caller]
    for called, duration in called_dict.items():
        called_str = str(called)
        # 处理被叫号码的反向记录
        if called_str not in call_dict:
            call_dict[called_str] = {caller: duration}
        else:
            if caller in call_dict[called_str]:
                call_dict[called_str][caller] += duration
            else:
                call_dict[called_str][caller] = duration

print(call_dict)

额外优化:统一所有号码为字符串类型,避免出现数字键和字符串键重复的问题(原字典中存在111111111数字键和'111111111'字符串键)

方案2:创建新字典存储结果

完全基于原字典的数据构建新字典,避免修改原字典,从根源上避免迭代时修改字典的问题。

代码实现:

call_dict = {
    '123456789': {'132456789': 583, '123546789': 444, '257918896': 528, '111111111': 495},
    '296358741': {'132456789': 631, '123456789': 98, '456789123': 395},
    111111111: {'123456789': 150}
}

result = {}

# 先处理所有主叫到被叫的记录
for caller, called_dict in call_dict.items():
    caller_str = str(caller)
    # 初始化主叫的条目
    if caller_str not in result:
        result[caller_str] = {}
    # 添加主叫到被叫的时长
    for called, duration in called_dict.items():
        called_str = str(called)
        result[caller_str][called_str] = result[caller_str].get(called_str, 0) + duration
        
        # 处理被叫到主叫的反向记录
        if called_str not in result:
            result[called_str] = {}
        result[called_str][caller_str] = result[called_str].get(caller_str, 0) + duration

print(result)

这种方法逻辑更清晰,也不会出现迭代时修改字典的问题,同时自动统一了号码的字符串类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 01:31:16