Python递归按时间区间拆分列表报递归深度超限如何修复
问题说明
场景说明
业务逻辑为采集用户观看拼接长视频的按键行为:用户每次按键时,记录当前视频播放位置的毫秒级时间戳存入列表。该长视频由多个时长20-60秒的独立试次(trial)视频拼接而成,系统无法识别试次边界,需根据已知参数拆分时间戳列表:
trials_num:试次总数量,即最终输出的子列表总个数trial_length:单个试次时长(单位:秒),转换为毫秒后作为区间步长,时间区间依次为0~trial_length*1000ms、trial_length*1000+1~2*trial_length*1000ms……以此类推,每个区间内的时间戳归入对应子列表,单个试次对应的时间戳数量无固定要求。
现有代码与问题
编写的递归函数break_lists代码如下:
def break_lists(orig_list, trial_length, trials_num, final_list): # 生成对应试次数量的遍历序列 t = [] for num in range(1, trials_num + 1): t.append(num) # 秒转毫秒计算单试次时长 ms_length = trial_length * 1000 # 遍历所有试次 for num in t: sublist = [] # 遍历列表前40个元素(单试次最多40个时间戳) for i in range(0, 40): if orig_list[i] <= ms_length * num: sublist.append(orig_list[i]) else: # 超出当前区间则递归处理剩余列表 break_lists(orig_list[i:], trial_length, trials_num, final_list) final_list.append(sublist) print(final_list) return(final_list)
测试用例:
- 输入时间戳列表:
[2000, 3000, 4000, 5000, 6000, 7000, 9000, 12000, 15000, 17000, 19000, 80000] - 调用方式:
break_lists(list, 5, 20, []) - 预期输出:
[[2000, 3000, 4000, 5000], [6000, 7000, 9000], [12000, 15000], [17000, 19000], [80000]]
运行代码时触发maximum recursion depth exceeded in comparison报错,调整代码后偶尔可运行,但会生成大量超出试次数量的多余空子列表,无法得到预期结果。
问题根因
原代码存在3个核心bug:
- 递归逻辑完全失控:每次进入递归都会重新遍历全部
trials_num个试次,没有记录当前处理到的试次序号,递归层数无限制增长直接触发栈溢出 - 硬编码单试次最多40个时间戳:单试次时间戳超过40个会触发索引越界,不足40个同样会报索引错误
- 没有列表切分标记:每次都是从传入列表的头部开始判断,不会移动处理位置,重复生成大量空的子列表
修复方案
这个场景完全不需要用递归,用移动指针顺序遍历的方式实现逻辑更简单,也不会有栈溢出问题:
def break_lists(orig_list, trial_length, trials_num): ms_length = trial_length * 1000 final_list = [] # ptr标记当前处理到原列表的位置 ptr = 0 total_ts = len(orig_list) # 逐试次匹配时间区间 for trial_idx in range(1, trials_num + 1): upper_bound = ms_length * trial_idx sublist = [] # 从当前指针位置向后找,所有落在当前区间的时间戳都归入子列表 while ptr < total_ts and orig_list[ptr] <= upper_bound: sublist.append(orig_list[ptr]) ptr += 1 # 非空子列表才加入结果,不需要多余空列表 if sublist: final_list.append(sublist) # 所有时间戳处理完直接退出,不用遍历剩余空试次 if ptr >= total_ts: break return final_list
测试验证
用给出的测试用例调用:
test_ts = [2000, 3000, 4000, 5000, 6000, 7000, 9000, 12000, 15000, 17000, 19000, 80000] print(break_lists(test_ts, 5, 20))
输出完全匹配预期:[[2000, 3000, 4000, 5000], [6000, 7000, 9000], [12000, 15000], [17000, 19000], [80000]]
补充说明:如果业务要求最终输出子列表数量必须严格等于
trials_num(即使后续试次无按键也要保留空列表),去掉sublist非空判断和提前退出的break逻辑即可。
内容的提问来源于stack exchange,提问作者AyeletK
相关产品推荐
相关产品推荐

