删除给定索引处的列表元素

我有一个列表,其中包含一些string类型的项目。

List lstOriginal; 

我有另一个列表,其中包含应从第一个列表中删除的id。

 List lstIndices; 

我试过用RemoveAt()方法完成这项工作,

 foreach(int indice in lstIndices) { lstOriginal.RemoveAt(indice); } 

但是它崩溃并且说我“索引超出范围”。

您需要对要从最大到最小返回的索引进行排序,以避免在错误的索引处删除某些内容。

 foreach(int indice in lstIndices.OrderByDescending(v => v)) { lstOriginal.RemoveAt(indice); } 

原因如下:假设有一个包含五个项目的列表,并且您想要删除索引24 。 如果首先删除2的项目,则索引4处的项目将位于索引3 ,索引4将不再位于列表中(导致您的exception)。 如果你倒退,所有索引都会在你准备删除相应项目的那一刻。

你是如何填写指数列表的? 您可以使用更高效的RemoveAll方法。 例如,而不是这样:

 var indices = new List(); 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)); 

这最大限度地减少了将项目复制到arrays中的新位置; 每个项目只复制一次。

您也可以在上面的示例中使用方法组转换,而不是lambda:

 data.RemoveAll(SomeFunction); 

之所以发生这种情况,是因为当您从列表中删除某个项目时,每个项目的索引会有效地减少一个,因此如果您按增加索引顺序删除它们,并且原始列表末尾附近的某些项目将是删除后,这些索引现在无效,因为删除前面的项目后列表会变短。

最简单的解决方案是按递减顺序对索引列表进行排序(最高索引优先),然后对其进行迭代。

 for (int i = 0; i < indices.Count; i++) { items.RemoveAt(indices[i] - i); } 
  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(); 

我的原位删除给定索引作为方便的扩展方法。 它只复制所有项目一次,因此如果要删除大量的标记,它会更加高效。

如果要删除的索引超出范围,它也会抛出ArgumentOutOfRangeException

  public static class ListExtensions { public static void RemoveAllIndices(this List list, IEnumerable 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); } } 
  lstIndices.OrderByDescending(p => p).ToList().ForEach(p => lstOriginal.RemoveAt((int)p)); 

作为旁注,在foreach语句中,最好不要修改运行foreach的Ienumerable。 超出范围的错误可能是由于这种情况造成的。