60.索引遍历移除List中元素结果
60.1 题目
请问执行以下代码后List中还存在哪些内容?
List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (int i = 0; i < numbers.Count; i++)
{
numbers.RemoveAt(i);
}
60.2 深入解析
执行代码后,List中还存在的内容为:2, 4, 6, 8, 10
详细说明:
这段代码不会抛出索引越界异常:i 从 0 递增,每次 RemoveAt 后 Count 减 1,循环约执行 原长度的一半 即停止。真正的问题是删除后元素前移,索引 i 会“跳过”本应访问的元素,因此只删掉了约一半元素。说明如下:
- 初始状态下,
numbers列表包含[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]。 - 循环开始,
i初始值为 0。
第一次迭代
i = 0,numbers.RemoveAt(0)被调用。numbers变成[2, 3, 4, 5, 6, 7, 8, 9, 10]。
第二次迭代
i递增到 1,numbers.RemoveAt(1)被调用。numbers变成[2, 4, 5, 6, 7, 8, 9, 10]。
第三次迭代
i递增到 2,numbers.RemoveAt(2)被调用。numbers变成[2, 4, 6, 7, 8, 9, 10]。
第四次迭代
i递增到 3,numbers.RemoveAt(3)被调用。numbers变成[2, 4, 6, 8, 9, 10]。
第五次迭代
i递增到 4,numbers.RemoveAt(4)被调用。numbers变成[2, 4, 6, 8, 10]。
第六次迭代
i递增到 5,numbers.Count现在是 5,不满足条件不会进循环体。- 循环结束
60.3 答题示例
“执行这段代码不会因索引越界抛异常,但结果不符合“删光全部元素”的预期。正向
for中RemoveAt(i)会使后续元素前移,下一轮i自增后跳过一个元素,只删除约一半。过程如下:
- 初始状态:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]- 第1次循环(i=0):删除索引0的元素1 → 列表变为
[2, 3, 4, 5, 6, 7, 8, 9, 10]- 第2次循环(i=1):删除索引1的元素3(原元素2前移至索引0) → 列表变为
[2, 4, 5, 6, 7, 8, 9, 10]- 第3次循环(i=2):删除索引2的元素5 → 列表变为
[2, 4, 6, 7, 8, 9, 10]- 第4次循环(i=3):删除索引3的元素7 → 列表变为
[2, 4, 6, 8, 9, 10]- 第5次循环(i=4):删除索引4的元素9 → 列表变为
[2, 4, 6, 8, 10]- 第6次循环(i=5):此时列表长度为5,
i < numbers.Count不成立,循环终止最终结果:剩余
[2, 4, 6, 8, 10]。正确删除可倒序遍历、用RemoveAll、或先拷贝再遍历,避免边遍历边删导致漏删。”
60.4 关键词联想
- 索引错位(Index Shift)
- 集合修改异常(Collection Modified Exception)
- 倒序遍历(Reverse Iteration)
ToList()复制(Shallow Copy)RemoveAll()方法List<T>内部数组调整- 并发集合(ConcurrentBag)
- 迭代器失效(Iterator Invalidated)
- 快速失败机制(Fail-Fast)
- 性能损耗(频繁数组重分配)
- 正确删除模式:
// 倒序遍历 for (int i = numbers.Count - 1; i >= 0; i--) {...} // 使用RemoveAll numbers.RemoveAll(x => x % 2 == 0);
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com