为何遍历列表时迭代器会跳过元素?求代码问题排查
迭代器跳过元素的原因及修复
问题根源
你代码里的核心问题是在for循环迭代列表的同时修改了原列表,导致迭代器的索引错位,跳过了元素。
具体过程:
- 初始
order是[1,1,3,3,7,2,2,2,2],for循环的迭代器按顺序遍历每个元素的索引。 - 第一次循环取索引0的
1,调用remove_from_list把所有1从order中删除,此时order变成[3,3,7,2,2,2,2]。 - 迭代器接下来要取索引1的元素,此时
order的索引1是3,处理完3后,所有3被删除,order变成[7,2,2,2,2]。 - 迭代器继续取索引2的元素,此时
order的索引2是2,直接跳过了索引0的7——这就是为什么7没被处理。
另外你的代码还有两个逻辑瑕疵:
else分支里调用remove_from_list(x, order)但没有重新赋值order,不过因为列表是可变对象,其实已经修改了原列表,但这个不影响核心问题。- 每次调用
order.count(x)和remove_from_list都是O(n)操作,整体时间复杂度很高,效率低下。
修复方案
不需要修改原列表,只需要遍历原列表时统计每个元素的出现次数,当次数未超过max_e时加入新列表,这样既不会打乱迭代顺序,效率也更高:
def delete_nth(order, max_e): count = {} new_list = [] for num in order: # 统计当前元素出现的次数,默认0 current_count = count.get(num, 0) + 1 count[num] = current_count # 未超过限制则加入新列表 if current_count <= max_e: new_list.append(num) return new_list print(delete_nth([1,1,3,3,7,2,2,2,2], 3)) # 输出:[1, 1, 3, 3, 7, 2, 2, 2]
原代码的另一种修改思路(不推荐)
如果你一定要保留修改原列表的逻辑,需要基于原列表的副本进行迭代,这样修改原列表不会影响迭代顺序:
from itertools import repeat def delete_nth(order, max_e): def remove_from_list(i, list1): if i in list1: list1.remove(i) return remove_from_list(i, list1) else: return list1 new_list = [] # 迭代原列表的副本,避免修改原列表影响迭代 for x in list(order): current_count = order.count(x) if current_count <= max_e: new_list.extend(repeat(x, current_count)) order = remove_from_list(x, order) else: new_list.extend(repeat(x, max_e)) order = remove_from_list(x, order) return new_list print(delete_nth([1,1,3,3,7,2,2,2,2], 3)) # 输出:[1, 1, 3, 3, 7, 2, 2, 2]
不过这种方式效率依然很低,还是推荐第一种方案。
内容的提问来源于stack exchange,提问作者Artjom Hramets
相关产品推荐
相关产品推荐

