Question

Duplicate

Modifying A Collection While Iterating Through It


Has anyone a nice pattern to allow me to get around the inability to remove objects while I loop through an enumerable collection (eg, an IList or KeyValuePairs in a dictionary)

For example, the following fails, as it modifies the List being enumerated over during the foreach

foreach (MyObject myObject in MyListOfMyObjects)
{
     if (condition) MyListOfMyObjects.Remove(myObject);
}

In the past I have used two methods.

I have replaced the foreach with a reversed for loop (so as not to change the any indexes I am looping over if I remove an object).

I have also tried storing a new collection of objects to remove within to loop, then looping through that collection and removed the objects from the original collection.

These work fine, but neither feels nice, and I was wondering if anyone has come up with a more elegant solution to the issue

Was it helpful?

Solution

There's a useful List<T>.RemoveAll(Predicate<T> match) method which I think is designed for this: http://msdn.microsoft.com/en-us/library/wdka673a.aspx

OTHER TIPS

It's kind of simple-minded, but when I plan to delete items from an IEnumerable/IList I usually just make a copy:

foreach (MyObject myObject in new List<MyObject>(MyListOfMyObjects))
{
     if (condition) MyListOfMyObjects.Remove(myObject);
}

It's not the most efficient way to do it, but it's easy to read. Premature optimization and all that.

Do the inverse, creating a new list:

List myFilteredList = new List();
foreach (MyObject myObject in myListOfMyObjects)
{
     if (!condition) myFilteredList.Add(myObject);
}

Then use the new list wherever you need it.

You can also use a LINQ expression easily, again, inversing the condition. This has the added benefit of not creating a new structure, but also the pitfalls of it being a lazy enumerable:

var myFilteredList = from myObject in myListOfMyObjects
                     where !condition
                     select myObject;

However, if you truly need to remove the items from the list, I typically use the "create a new list, then reiterate and remove" approach.

I just came across this post and thought I would share.

void RemoveAll(object condition)  
{

    bool found = false;

    foreach(object thisObject in objects)    
    {

        if (condition)    
        {    
            objects.Remove(thisObject);

            found = true;

            break; //exit loop    
        }     
     }

    // Call again recursively

    if (found) RemoveAll(condition);

}

I don't like the reversed for loop idea, since that only works on certain data structures.

In general I'd use the second technique and accumulate the items to be deleted in a separate 'to-be-deleted' collection. If deletion can cause existing iterates to be invalidated (as will happen with any balanced tree collection for example) then I don't see a way around this.

The only other technique that I've occasionally used is to restart the whole iteration when you find the first element to delete. If you make it through without finding any items to delete then the function is finished. This is inefficient, but sometimes neccessary if deleting one item from the collection may change the set of items that need to be deleted.

I have a dictionary and want to Dispose of all Values. When each value is disposed it removes itself from the dictionary which creates the problem you discuss. I did the following:

foreach (var o in dictionary.Values.ToList())
{
  o.Dispose();
}

I appreciate this may be dead now but the way I always do this is:

foreach (MyObject myObject in MyListOfMyObjects)
{

if (condition) MyListOfMyObjects.Remove(myObject);

break;

}

Object is removed and then loop exits, viola!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top