Take the 2-minute tour ×

I have a list which contains some items of type string.

List<string> lstOriginal;

I have another list which contains idices which should be removed from first list.

List<int> lstIndices;

I'd tried to do the job with RemoveAt() method ,

foreach(int indice in lstIndices)

but it crashes and said me that "index is Out of Range."

Please suggest me how can I do this job. Thank you!

share|improve this question
where are the list of indices coming from? because you delete indices that aren't in the list –  Frederiek Mar 28 '12 at 13:32
When you remove an item, it changes the indices of items that come after it. If you have indices 1 and 3, when you remove one, index 3 no longer points to the same object. It could now be out of bounds, which is why you get that exception. –  SomeWritesReserved Mar 28 '12 at 13:33
This is crashing because when you remove the first item from the list, all of the indices change accordingly. –  bporter Mar 28 '12 at 13:33
When is the lstIndices populated? –  user959631 Mar 28 '12 at 13:36
THANK YOU GUYS, THANK YOU!!! –  meorfi Mar 28 '12 at 13:54
add comment

6 Answers

up vote 13 down vote accepted

You need to sort the indexes that you would like to return from largest to smallest in order to avoid removing something at the wrong index.

foreach(int indice in lstIndices.OrderByDescending(v => v))

Here is why: let's say have a list of five items, and you'd like to remove items at indexes 2 and 4. If you remove the item at 2 first, the item that was at index 4 would be at index 3, and index 4 would no longer be in the list at all (causing your exception). If you go backwards, all indexes would be there up to the moment when you're ready to remove the corresponding item.

share|improve this answer
This would work but it would be mo efficient to go in a for loop over the indices, and removing index-i –  Yorye Nathan Mar 28 '12 at 13:34
@YoryeNathan that assumes that the indexes in the list are already in ascending order. If they're unordered you need to do some type of sort. –  Servy Mar 28 '12 at 13:36
@Servy If the indices to remove are not sortd, it won't work eother way. He must sort them in both ways, unless he knows that they are in order. IF they are ALREADY in descending order, then a simple loop will do, but then he wouldn't have this problem so this is not the case anywyas. –  Yorye Nathan Mar 28 '12 at 13:39
this is good answer. Thank you dasblinkenlight –  meorfi Mar 28 '12 at 13:44
@YoryeNathan well of course an orderby call sorts the data. If it's merely performance considerations, as I said, the sort algorithm used is optimized for that case, so it will have O(n) performance. Additionally no need to prematurely optimize. Obvious correctness and code simplicity/readability is more than worth it unless the data is huge. If there really are performance consideration the whole design should be re-considered. –  Servy Mar 28 '12 at 14:55
show 2 more comments

How are you populating the list of indices? There's a much more efficient RemoveAll method that you might be able to use. For example, instead of this:

var indices = new List<int>();
int index = 0;
foreach (var item in data)
    if (SomeFunction(data))

//then some logic to remove the items

you could do this:

data.RemoveAll(item => SomeFunction(item));

This minimizes the copying of items to new positions in the array; each item is copied only once.

You could also use a method group conversion in the above example, instead of a lambda:

share|improve this answer
add comment

The reason this is happening is because when you remove an item from the list, the index of each item after it effectively decreases by one, so if you remove them in increasing index order and some items near the end of the original list were to be removed, those indices are now invalid because the list becomes shorter as the earlier items are removed.

The easiest solution is to sort your index list in decreasing order (highest index first) and then iterate across that.

share|improve this answer
add comment
    items.RemoveAt(indices[i] - i);
share|improve this answer
This assumes the list is sorted in ascending order. In that case, would be more efficient to do for (int i = indices.Count - 1; i >= 0; i--). Why is that? Because the items after the index have to be copied to the previous position. There's less copying if you start at the end than if you start at the beginning, because if you start at the beginning, you're also copying items that you are about to remove. –  phoog Mar 28 '12 at 13:41
this is good answer. But the list should be sorted. Thank you Yorye Nathan –  meorfi Mar 28 '12 at 13:44
Reallocation will not differ between these approaches, but your loop is indeed more readable. And of course, you do one less atomic calculation, so perfectionalism calls you to win. –  Yorye Nathan Mar 28 '12 at 13:45
@meorfi in writing my previous comment, I remembered the RemoveAll method, which reduces the copying overhead even further. It's not clear from the question whether it can be applied here, however. –  phoog Mar 28 '12 at 13:50
add comment
        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();
share|improve this answer
add comment
 lstIndices.OrderByDescending(p => p).ToList().ForEach(p => lstOriginal.RemoveAt((int)p));

As a side note, in foreach statements, it is better not to modify the Ienumerable on which foreach is running. The out of range error is probably as a result of this situation.

share|improve this answer
This is incorrect: the out of range error is a result of the fact that removing items changes the index of other items, and this solution doesn't fix that. For example, suppose you wanted to remove the items at indexes 5 and 6. You could either call RemoveAt(6) and RemoveAt(5), in that order, or you could call RemoveAt(5) and RemoveAt(5) in that order. –  phoog Mar 28 '12 at 13:44
@phoog you may be right on this context, on the otherhand, it is better not to modify the enumerable in a foreach loop on which same list is enumerated. –  daryal Mar 28 '12 at 13:50
I have updated. –  daryal Mar 28 '12 at 13:51
@daryal It's not modifying the list that's being enumerated. There are two lists. The one being enumerated is different than the one being modified. –  Servy Mar 28 '12 at 14:10
@Servy sorry to miss that point. –  daryal Mar 28 '12 at 14:14
add comment

Your Answer


