为何移除列表中21~32范围元素的代码会触发IndexOutOfRangeException异常?
解决List移除元素时的IndexOutOfRangeException问题
嘿,我来帮你理清这个索引越界的问题!作为有4年经验的开发者,这种看似简单的遍历移除坑确实容易踩中~
问题根源
你代码的核心问题在于固定循环次数(硬写了k < 6)和移除元素后List长度动态变化的矛盾:
- 当你调用
changedNums.RemoveAt(k)时,List的长度会立刻减1,后续元素会向前移动一位填补被移除的位置。 - 但你的循环还是坚持跑满6次,而且
k一直在递增。比如,当你移除第0个元素后,List长度变成5,但k会继续走到5,此时访问changedNums[5]自然会触发IndexOutOfRangeException。 - 另外,正向遍历移除还会导致你跳过元素:比如移除第0个元素后,原来的第1个元素现在在第0位,但
k变成1,直接跳过了这个元素的检查。
三种解决方案
1. 反向遍历(最稳妥的手动遍历方式)
从List的最后一个元素往前遍历,这样移除元素不会影响前面未遍历的元素索引,既不会跳过元素,也不会出现越界:
// nums是一个恰好包含6个元素的List<int> List<int> changedNums = new List<int>(nums); for (int k = changedNums.Count - 1; k >= 0; k--) { if (changedNums[k] >= 21 && changedNums[k] <= 32) { changedNums.RemoveAt(k); } }
2. 使用LINQ过滤(最简洁的方式)
直接用LINQ的Where方法过滤掉目标范围的元素,一行代码搞定,完全避免手动遍历的索引问题:
// nums是一个恰好包含6个元素的List<int> List<int> changedNums = nums.Where(num => num < 21 || num > 32).ToList();
3. 正向遍历但动态调整索引(适合必须正向遍历的场景)
如果一定要正向遍历,需要在移除元素时调整k的取值,同时用List的实时长度作为循环条件:
// nums是一个恰好包含6个元素的List<int> List<int> changedNums = new List<int>(nums); int k = 0; while (k < changedNums.Count) { if (changedNums[k] >= 21 && changedNums[k] <= 32) { changedNums.RemoveAt(k); // 移除元素后,下一个元素移到当前k的位置,所以不递增k } else { k++; // 不需要移除时,再移动到下一个元素 } }
总结
你的原代码用固定的6次循环没有考虑List长度的动态变化,加上正向遍历移除的索引偏移问题,才导致了越界异常。上面的三种方法都能完美解决这个问题,其中LINQ的方式最简洁易读,推荐优先使用~
内容的提问来源于stack exchange,提问作者Benjamin Zvolenszki
相关产品推荐
相关产品推荐

