Removing items in a list while iterating through it

See the following code:


List<int> list = new List<int>();

for (int i = 1; i < 10; i++)
{
list.Add(i);
}

foreach (int i in list)
{
list.Remove(i);
}

Do you see anything wrong in this piece of code? No? Okay.

Execute this code and you will get a System.InvalidOperationException with the message “Collection was modified; enumeration operation may not execute.”

The first time foreach loop executes, it deletes the first item and in the second iteration, this nasty exception is thrown. Reason? You deleted the first item and the list has changed. If not for the InvalidOperationException , you could have got a IndexOutOfRange exception while traversing the list.

So, how does one delete some items in the list while iterating through the list? I faced this problem in my project today and I couldn’t come up with an elegant solution. I did come up with a hack. I identify all items that need to be deleted and mark them with a flag (I need one iteration here). In another iteration, I create a new list and copy all those items which are not marked.

Sorry, I couldn’t come up with something better. If you have a solution or a better fix, please do let me know. Please note that if I want to remove all items, I can use list.Clear(). I am talking about a scenario where I want to delete only a select few items.

Update:

I read somewhere that if you use for loop instead of foreach, this problem does not arise. True, you will not get an exception, but you might not delete the items that you actually want to delete. Let’s see what happens in our case.


List<int> list = new List<int>();

for (int i = 1; i < 10; i++)
{
list.Add(i);
}

for (int i = 0; i < list.Count; i++)
{
int remove = list[i];
list.Remove(remove);
}

You will delete items 1, 3, 5, 7 and 9. After the for loop exits, your list will still have 2, 4, 6 and 8. Surprised?

Let’s see why this is so.

First iteration: i = 0, remove = 1. Deleted item = 1 Once you delete this item, the list has changed. So, the first element in the list is now 2.
Second iteration: i = 1, remove = 3. Deleted item = 3
Third iteration: i = 2, remove = 5. Deleted item = 5

and so on….

So, replacing foreach with a for is not a solution.

About these ads

72 thoughts on “Removing items in a list while iterating through it

  1. Tony says:

    Can you not use the ‘for’ method but loop backwards over the list removing them one at a time?

    This should overcome the elements shifting into the position of those deleted.

  2. Z says:

    That’s what I do.

    for(int i=10 ; i>0 ; i–)
    Remove(i);

  3. Josh says:

    For most cases like this, you can use delegates:

    //removes all even numbers from list:
    NumberList.RemoveAll(delegate(int x) { return x%2 == 0; });

  4. Pxtl says:

    Reverse-iteration is, traditionally, the “proper” way to do a For-loop that removes elements from the list.

    Personally, though, I tend to just use delegates, if you’re lucky enough to be using the List class.

  5. captainrandom says:

    What I end up doing is making a copy of the list, removing the needed items from the copy, and then replacing the original with the copy to avoid this problem.

  6. gjunky says:

    You can also just delete entry 0 (zero) in the for loop instead of deleting the i entry. Each time you look and remove index=0, you will create a “new” zero entry. You could of course set the count to zero…

  7. Anaamica says:

    gjunky, this works if I want to delete all the items in the list. What if I want to delete some items depending on some condition?

  8. jean says:

    I use the more elegant “black list”:
    List remList = new List();
    foreach (TestClass tc in list)
    if (hasToBeDeleted) remList.Add(tc);

    list.RemoveAll(new Predicate(delegate(TestClass x) { return remList.Contains(x);}));

  9. I use a different approach, create a second list that “filtter” the items that must be removed and then replace the original list with the new one.

    Basically is like “filtering” instead of “removing”, the cons is that you must recreate the list but I think the Add operation for List must not be so heavy.

    Here is an example (observe the ! preceding the condition that indicates which items must be removed, it is negative logic!):

    //Orignal List
    List list = new List();
    for (int i = 1; i < 10; i++)
    {
    list.Add(i);
    }

    //Filtered List
    List newList = new List();
    foreach (int i in list)
    {
    if (! MustRemove(i))
    newList.Add(i);
    }

    //Replacing the original list
    list = newList;

    Regards.

  10. Fredrik says:

    I like this gentleman’s approach; wrap it up ina isloator class that lets you modify the items of the list while iterating it:
    http://www.koders.com/csharp/fidF2C8E1786AE76101911914CCA9286E25B398AED6.aspx

  11. Shrikanth Hulisandra says:

    What I do is, during the first iteration, I get the lndexes of elements that i want to remove and then call the following function :

    private void removeElementsFromList(List list, List indexOfElementsToBeRemoved)
    {
    try
    {
    Collections.sort(indexOfElementsToBeRemoved);

    Iterator indexes = indexOfElementsToBeRemoved.iterator();

    int counter = 0;
    while(indexes.hasNext())
    {
    int updatedIndexOfItemToBeRemoved = indexes.next() – counter;
    list.remove(updatedIndexOfItemToBeRemoved);
    counter++;
    }
    }
    catch (Exception e)
    {
    }
    }

  12. NBJack says:

    I have a recommendation. Borrowing from the other site in question, I recommend this approach:

    int t = 0;
    object o;

    while ( t < list.count )
    {
    o = list[t];

    if ( o.shouldDelete() )
    list.remove(o);
    else
    t++;
    }

    You’ll either run out of elements or get to the end of the list.

    • ddf says:

      your code aint correct, just check if you have a list with four elements, in the case that all elements must be removed you will have:

      1st iteration:
      t = 0 § Count = 4
      t = 1 § Count = 3
      t = 2 § Count = 2 => You’re able to remove only half of the total quantity you were supposed to remove ..

      • dw says:

        Actually, the code is corret… you aint.
        t is not getting incremented when an item is removed. Removing all is:
        Count = 4, t = 0 -> Count = 3, t = 0 -> Count = 2, t = 0 -> Count = 1, t = 0 -> Count = 0.
        All 4 elements are removed.

        int i = 0;
        while (i < list.Count)
        {
        if (ShouldRemove(list[i]))
        list.RemoveAt(i);
        else
        i++;
        }

  13. adam says:

    maybe list.Clear();
    ?

  14. raylu says:

    Using the for solution, only increment if you didn’t remove.

  15. emilsebastian says:

    I think Josh’s solution using a delegate is the most elegant. However, if delegates are not an option, why not iterate over a copy of the original list? That way you’d come up with something looking pretty close to what you originally wanted to do …

    foreach (int i in new List(list))
    {
    list.Remove(i);
    }

    Far more readable than the “black list” approaches above IMHO and you can avoid having to manually maintain a list index until you really need to for performance reasons.

  16. emilsebastian says:

    Oops, the generic list declaration was stripped by WordPress … I’ll try again :-)

    foreach (int i in new List<int>(list))
    {
    list.Remove(i);
    }

  17. HarmonicStyle says:

    It’s easier than that. This works for both foreach and for loops.

    // Create 2 lists.
    new List
    new ListDeletions

    // Iterate through the loop
    For each item in list
    if condition is met add this to listDeletions

    // When the loop is finished update List
    List.Except(ListDeletions)

    It’s called Linq and it works for removing any specific entries in any order

    What you guys are talking about is a FIFO list aka. Queue. You could do like a previous comment said. Create a for loop and loop through the entries in reverse order removing the items after they have been processed. The downside of this is is creates a LIFO list aka. stack. So, to reverse it, you’d have to duplicate the original list in the reverse order to actually create a queue.

    I can vouch that both these methods work because I have used both. If you use the for Stack it is more performant but less flexible.

    There are also specific classes that are tied into iEnumerable. Called Stack and Queue (go figure).
    You can find specifics on how to use queue here:
    http://www.blackwasp.co.uk/Queue.aspx

    And how to use the stack here:
    http://www.blackwasp.co.uk/Stack.aspx

    There’s also a Freemind MindMap for C# Here:
    freemind.sourceforge.net/wiki/extensions/freemind/flashwindow.php?startCollapsedToLevel=3&initLoadFile=/wiki/images/e/ee/CSharp_2_WebLinks2.mm&mm_title=C%23%202.0%20Computer%20Language%20-%20Contents

    You can find it in the MindMap under C# 2.0 Collections

    There’s no need to re-invent the wheel, unless you need a custom implementation that performs better.

    If you work with iEnumerables a lot I suggest you learn Linq-To-Objects, it will save you an untold amount of dev time. Check out [2008 – Apress – LINQ For Visual C Sharp 2008. It’s the only decent book resource I’ve found on the subject so far.

    • rswank says:

      A++++++++++
      This is the best way!
      I have a List of session items and a user created subset of items (via checkboxes of the original list).
      After an action occurs on the subset I need to remove them from the session list before rebinding to the datalist.
      This is PERFECT!

  18. Ian says:

    delegates are definately the best approach and now you have the benefit of lamda expressions which are even more concise and elegant.

  19. bobobobo says:

    what about for dictionary?

    you can’t normal for() loop over it, apparently

  20. Neil J says:

    thanks for the delegate code here… ive never used it befre and i just did! I am writing a game in C# and XNA and keeping track of bullets fired and managed by my ObjectManager class. This allows me to delete ‘dead’ projectiles instead of reusing them- thanks for the idea!

  21. Rich says:

    The issue I had was editing an object in the list, and possibly removing it on a condition. Not sure if a delegate would work. I did as follows:

    List MyList;
    ObjClass [] temp = new ObjClass[MyList.Count];
    ObjClass.CopyTo(temp);

    foreach (ObjClass obj in temp)
    {
    //if condition met, modifiy obj properties
    obj.x = … obj.y = …
    //if other condition met, remove obj
    MyList.Remove(obj);
    }

  22. Igor says:

    It is as easy as unbinding the list from foreach. Just add ToArray() to the list

    List list = new List();

    for (int i = 1; i < 10; i++)
    {
    list.Add(i);
    }

    foreach (int i in list.ToArray())
    {
    list.Remove(i);
    }

  23. DDtMM says:

    The reverse for loop is the fastest method:

    for (int idx = list.Count – 1; idx >= 0; idx–)
    {
    if (list[idx].Remove()) list.RemoveAt(idx);
    }

    1) The Count property is called only once. In a foward loop it would be called after each iteration, or you would have to assign it to a variable before hand.
    2) RemoveAt() has better performance than Remove().
    3) Though I wouldn’t know for sure, my instinct is that ForEach is slower that For.
    4) Obviously solutions that copy lists to other lists, will be adding all sorts of weight to the procedure. And though it doesn’t appear to be the case, methods like list.ToArray() are doing just that.

    It’s not that ugly in my opinion.

  24. To remove selected item in multiselect list box:
    for (int i=lbx_ProdMaster.Items.Count ; i>0 ; i–)
    {
    if(lbx_ProdMaster.Items[i-1].Selected == true)
    {
    lbx_ProdMaster.Items.RemoveAt(i-1);
    }
    }

  25. Mark says:

    This annoys me to no end.

    The proper (imho) way to do this is to use a LinkedList (either use the default one or roll your own). This kind of dynamic modification is what linked structures were designed for.

    However, there really SHOULD be a higher level abstraction for doing this kind of enumeration.

    The “for each” syntax is very elegant to use, but its associated semantics are too restrictive. I think it should work the same way a linked list works, which is that you can make any modifications you want to the list while enumerating, and there’s always a fixed marker for where you currently are in the list, whose absolute position may change with the changes made to the list.

    That way, there would be no indexing errors, although you wouldn’t be able to guarantee that the “for each” would ever terminate (i.e. might get an infinite loop). But this is a lesser evil.

  26. The best solution could be using While loop.
    While (list it not empty)
    {
    Delete First item
    }

    this will not give exception at all.

    Jayvardhan Patil
    http://codeforfuture.com

  27. Squimball says:

    The reverse iteration is just what I needed. I would’ve never thought of trying that. Thanks!

  28. Nick says:

    Holy cow, it’s is just appalling to see so many solutions that reek of disregard to runtime efficiency! Josh has posted a clean and solution. All solutions that include copying, converting to arrays etc are almost as bad as the sort of solutions that PHP and BASIC coders come up with.

    When there are methods already present in the .NET library, *use them*. Just like Josh does. That’s what they’re there for.

  29. MaxCulpa says:

    All solutions that manually grind though the list with for or while loops are “procedurally oriented”. You should just use the RemoveAll method provided in the List class.

    Example:

    playerShots is a list of Shot objects for a game. Location is a Point that is a property of a Shot. The following code removes all shots from the playerShots list that have reached the top of the screen…

    playerShots.RemoveAll(delegate(Shot s)
    {
    return s.Location.Y < 0;
    });

    Let C# work for you.

  30. MaxCulpa says:

    Yep, Josh is right.

  31. Rich says:

    foreach (ClientHandler client in clientList.Reverse())
    {
    if (client.IsDone())
    {
    clientList.Remove(client);
    }
    }

  32. Kabayongtao says:

    Good day guys, Josh’s solution worked for me, but I am having a hard time understanding the concept behind delegates. Can anyone give a simple explanation behind it? Thanks.

  33. Ferhat Akgün says:

    Why don’t you do it like this?
    for(int i = 0; i < mylist.Count; i++)
    {
    if(mycondition)
    {
    mylist.Remove(mylist[i--]);
    }
    }

    Every time you remove sth from mylist the property Count will be decreased and i too.
    The var i will point on the element right after the deleted one. So nothing will be skipped….

    Right?

  34. Niels says:

    I used this to remove image locations from a list:

    for (int j = 0; j < imageLocation.Count; j++)
    {
    imageLocation.RemoveAt(0);
    j–;
    }

  35. Kirill says:

    You are an idiot. When deleting items like

    08 for (int i = 0; i 0)
    {
    list.RemoveAt(0);
    }

  36. Kirill says:

    don’t forget to decrement i. The easiest way is to use ‘while’ loop while Count > 0

  37. NSFW says:

    public static class Extensions
    {
    public static IEnumerable Mutable(this List list)
    {
    int counter = 0;
    int size = list.Count;
    while (counter < size)
    {
    if (list.Count != size)
    {
    counter -= size – list.Count;
    size = list.Count;
    }
    yield return list[counter++];
    }
    }
    }

    List list = new List();
    list.Add(null);
    list.Add(null);
    list.Add(null);

    foreach (object one in list.Mutable())
    {
    list.Remove(one);
    }

    No error..

    Attempts to modify the index as if you deleted from the current position or less.

    Maybe a little dangerous though!

  38. Dave Thomas says:

    Try this less code:
    Use the class System.Collections.IEnumerator

    IEnumerator iterator = list.GetEnumerator();
    do
    {
    //In here you could some kind of check
    //For which items you want to remove list.Remove(iterator.Current);
    } while (iterator.MoveNext());

  39. Rolf van Musscher says:

    You can also do something like this:
    list.Where().ToList().Foreach(item => list.Remove(item));

  40. manohar says:

    List list = new ArrayList();
    Student s = null;
    for(int i=0;i<10;i++) {
    s = new Student();
    s.setName("name-"+i);
    list.add(s);
    }

    System.out.println(list);
    for(int i=0;i<list.size();i++) {

    if(list.get(i).getName().equals("name-3") || list.get(i).getName().equals("name-4") || list.get(i).getName().equals("name-7") || list.get(i).getName().equals("name-0") || list.get(i).getName().equals("name-2") || list.get(i).getName().equals("name-1") || list.get(i).getName().equals("name-9")) {
    list.remove(i);
    i–;
    }
    }
    System.out.println(list);

  41. fms says:

    Or now you can call RemoveAll() using a predicate for your particular case.

  42. Jety says:

    Thank you for this post, it helped me I faced the same issue. I first tried the delegate solution:
    Shapes.RemoveAll(delegate(Shape shapeToDelete) { return shapeToDelete.Count shapeToDelete.Count < MinimalShapePixels);
    Pretty cool :)

  43. Joarder Mohammad Mustafa Kamal says:

    iList.dataList.RemoveAll(delegate(Data x){return (x.dataIndex == m || x.dataIndex == n);});

    m and n are the index of iList those I wanted to delete. Thanks for this great post

    dataIndex is a custom property of custom structure Data which forms a custom List in dataList

  44. Alex says:

    I would typically use a reverse for loop, but if you have to traverse the list in the original order, then just make a small change to the incrementing:

    for( int i = 0; i < list.Count; i ++ )
    {
    if( list[i].shouldBeRemoved() )
    {
    list.RemoveAt(i–);
    }
    }

  45. Cameron says:

    why don’t you just try this if you’re wanting to delete an item?

    int i = 0;
    while (i != list.Count) {
    if ( list[i] fits the condition to be deleted ) {
    list.erase(i);
    }
    else {
    i++;
    }
    }

  46. Am says:

    Why not keep it simple?

    fooBar.RemoveAll(o => o.foo == bar);

  47. SiracGamer says:

    Wow, Deleting backwords is an excellent solution ! :D

  48. pooch says:

    wow 4 years old and still looking for newer wheels

  49. [...] had me stumped for a good 5 min until I found the following post by a guy having a similar issue “http://generally.wordpress.com/2007/10/24/removing-items-in-a-list-while-iterating-through-it/”, this did not solve the issue but a comment in it [...]

  50. DanielHeth says:

    I found the easiest thing to do is add a subtraction within the loop…
    here i am iterating through a list removing everything…

    for (int i = 0; i < modules.Count; i++)
    {
    modules[0].Close();
    i–;
    }

  51. catalyst says:

    why not remove with this?

    for (int i = 0; i < list.Count; i++)
    {
    int remove = list[i]; //this assigns list[0] to remove
    list.Remove(remove); //this deletes list[0]
    i–; //this makes sure the next element will be the next element ;)
    }

  52. catalyst says:

    or even simplier!

    for (int i = 0; i < list.Count; i++)
    {
    list.Remove(list[i]); //this deletes list[0]
    i–; //this makes sure the next element will be the next element
    }

  53. Yoni says:

    But everytime you remove an item from the list you can do I– operation.

  54. sonjz says:

    Thanks the ToList() posted in the comments fixed this for me:

    returnValue.ToList().ForEach(delegate(Item item) {
    if (item.Active)
    returnValue.Remove(item);
    });

    The problem I had before was not using ToList() and it was resizing the original list.

  55. amc says:

    Just add a i–; each time you remove something …

  56. Rafał says:

    Actually “for” is very straightforward:

    for (int i = 0; i = 0; –i )
    {
    if( shouldRemove( list[ i ] ) )
    {
    list.Remove( i );
    }
    }

  57. John Mott says:

    I figured out how to do this recursively, should be fine for short lists.

    List intList = new List ();
    // add some items

    RecursiveDelete(0);

    public void RecursiveDelete(int index)
    {
    // check for end point
    if (index == intList.Count) return;

    // Get this value (happens before any deletes)
    int v = intList[index];

    // Recurse
    RecursiveDelete(index + 1);

    // Possibly delete this value
    if (condition) intList.Remove(v);

    }

  58. E. Joe Wright says:

    ‘How about this? Pretty short, clean and straight forward.

    For i = 0 To lst.Count – 1
    If bolYourCondition Then
    lst.RemoveAt(i- iRemoveCnt) ‘Remove
    iRemoveCnt += 1
    End If
    Next

  59. E. Joe Wright says:

    And if you have a forward looping for structure already there is not need to change it.

  60. Create a new list:
    var newList = myList.ToList();
    foreach(var item in newList) myList.Remove(item);

    not one curly!

  61. “Removing items in a list while iterating through it | Codelicious” was indeed a fantastic posting.

    If merely there was more weblogs like this amazing one on the
    net. Well, many thanks for ur precious time, Lolita

  62. [...] had me stumped for a good 5 min until I found the following post by a guy having a similar issue “http://generally.wordpress.com/2007/10/24/removing-items-in-a-list-while-iterating-through-it/”, this did not solve the issue but a comment in it did.Here is my complete [...]

  63. Panic attacks are serious and can make a person feel like they
    are out of control, having a heart attack, or like they cannot
    breathe. All this is to help set up your body and mind to be faster, stronger and more alert, i.

    After my senior year and graduating, barely, I was on my own to face the world.

  64. Bunzaga says:

    I use a doubly linked list for situations like this.

    var n = list.first;
    while(n != null){
    // add or remove here
    n = n.next;
    }

    If you remove an item, ‘n.next’ points to the next node. If you add an element, it tacks it onto the end of the list. For iteration or adding and removing while iterating, a doubly linked list is awesome. However, if you want to look up elements based on an index, it can be slow if you don’t implement your own lookup system…

    For example a separate hash with indexes pointing directly to nodes within the list.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: