60.索引遍历移除List中元素结果

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 递增,每次 RemoveAtCount 减 1,循环约执行 原长度的一半 即停止。真正的问题是删除后元素前移,索引 i 会“跳过”本应访问的元素,因此只删掉了约一半元素。说明如下:

  1. 初始状态下,numbers 列表包含 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  2. 循环开始,i 初始值为 0。

第一次迭代

  • i = 0numbers.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 答题示例

“执行这段代码不会因索引越界抛异常,但结果不符合“删光全部元素”的预期。正向 forRemoveAt(i) 会使后续元素前移,下一轮 i 自增后跳过一个元素,只删除约一半。过程如下:

  1. 初始状态[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  2. 第1次循环(i=0):删除索引0的元素1 → 列表变为[2, 3, 4, 5, 6, 7, 8, 9, 10]
  3. 第2次循环(i=1):删除索引1的元素3(原元素2前移至索引0) → 列表变为[2, 4, 5, 6, 7, 8, 9, 10]
  4. 第3次循环(i=2):删除索引2的元素5 → 列表变为[2, 4, 6, 7, 8, 9, 10]
  5. 第4次循环(i=3):删除索引3的元素7 → 列表变为[2, 4, 6, 8, 9, 10]
  6. 第5次循环(i=4):删除索引4的元素9 → 列表变为[2, 4, 6, 8, 10]
  7. 第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

×

喜欢就点赞,疼爱就打赏