我有一个列表,其中包含一些string类型的项目。
List<string> lstOriginal;
我有另一个列表,其中包含应从第一个列表中删除的id。
List<int> lstIndices;
我尝试用 RemoveAt()方法完成这项工作,
foreach(int indice in lstIndices)
{
lstOriginal.RemoveAt(indice);
}
但它崩溃并且告诉我“索引超出范围。”
答案 0 :(得分:30)
您需要对要从最大到最小返回的索引进行排序,以避免删除错误索引处的内容。
foreach(int indice in lstIndices.OrderByDescending(v => v))
{
lstOriginal.RemoveAt(indice);
}
原因如下:假设有一个包含五个项目的列表,并且您要删除索引2
和4
的项目。如果您首先删除2
处的项目,则索引为4
的项目将位于索引3
,而索引4
将不再位于列表中(导致你的例外)。如果你倒退,所有索引都会存在,直到你准备删除相应的项目为止。
答案 1 :(得分:6)
您如何填充指数列表?您可以使用更高效的RemoveAll
方法。例如,而不是:
var indices = new List<int>();
int index = 0;
foreach (var item in data)
if (SomeFunction(data))
indices.Add(index++);
//then some logic to remove the items
你可以这样做:
data.RemoveAll(item => SomeFunction(item));
这最大限度地减少了将项目复制到阵列中的新位置;每个项目只复制一次。
您还可以在上面的示例中使用方法组转换,而不是lambda:
data.RemoveAll(SomeFunction);
答案 2 :(得分:5)
发生这种情况的原因是,当您从列表中删除某个项目时,每个项目的索引会有效地减少一个,因此如果您按增加的索引顺序删除它们,而某些项目接近原始列表的末尾要删除,这些索引现在无效,因为删除前面的项目后列表会变短。
最简单的解决方案是按递减顺序对索引列表进行排序(最高索引优先),然后对其进行迭代。
答案 3 :(得分:5)
for (int i = 0; i < indices.Count; i++)
{
items.RemoveAt(indices[i] - i);
}
答案 4 :(得分:1)
var array = lstOriginal.ConvertAll(item => new int?(item)).ToArray();
lstIndices.ForEach(index => array[index] = null);
lstOriginal = array.Where(item => item.HasValue).Select(item => item.Value).ToList();
答案 5 :(得分:1)
我就地删除给定索引作为方便的扩展方法。它只复制所有项目一次,因此如果要移除大量的标记,它会更加高效。
如果要删除的索引超出范围,它也会抛出ArgumentOutOfRangeException
。
public static class ListExtensions
{
public static void RemoveAllIndices<T>(this List<T> list, IEnumerable<int> indices)
{
//do not remove Distinct() call here, it's important
var indicesOrdered = indices.Distinct().ToArray();
if(indicesOrdered.Length == 0)
return;
Array.Sort(indicesOrdered);
if (indicesOrdered[0] < 0 || indicesOrdered[indicesOrdered.Length - 1] >= list.Count)
throw new ArgumentOutOfRangeException();
int indexToRemove = 0;
int newIdx = 0;
for (int originalIdx = 0; originalIdx < list.Count; originalIdx++)
{
if(indexToRemove < indicesOrdered.Length && indicesOrdered[indexToRemove] == originalIdx)
{
indexToRemove++;
}
else
{
list[newIdx++] = list[originalIdx];
}
}
list.RemoveRange(newIdx, list.Count - newIdx);
}
}
答案 6 :(得分:-2)
lstIndices.OrderByDescending(p => p).ToList().ForEach(p => lstOriginal.RemoveAt((int)p));
作为旁注,在foreach语句中,最好不要修改运行foreach的Ienumerable。超出范围的错误可能是由于这种情况造成的。