2

There is a typical collection of some class objects e.g. string for a simplicity

IList<string> collection = new List<string>();

During the program flow some function needs to operate on the collection, process class object and depending on the result of operation remove processed class object from collection.

E.g. following example of strings if string is "failed" then remove that item

foreach (string str in collection)
{
    // operate on the current class object
    // if str is not valid
    if (str == "failed")
        collection.Remove(str);
}

By all means that leads to exception. What is the best way to loop thru all elements having ability to remove it during enumeration?

Chesnokov Yuriy
  • 1,760
  • 5
  • 21
  • 35

3 Answers3

5

Do an indexed for loop, but do it backwards, because when you delete members the indexes upstream get changed.

e.g, for your string collection example:

for (int i = collection.Count() - 1; i >= 0; i--)
{
    // do some other stuff, then ...

    if (collection[i] == "failed")
        collection.RemoveAt(i);
}

NB: if you use a forward for-loop, it may appear to work at first, but it will skip an item after each remove (because of the way indexes get renumbered after a remove). So a common symptom of that bug is that removes appear to work until you get two adjacent ones. That can be quite a confusing bug. Not that its ever happened to me *cough*

codeulike
  • 22,514
  • 29
  • 120
  • 167
1

For List<> collections you can use RemoveAll.

collection.RemoveAll ( item => item == "failed" );

For generic IEnumerable<> collections you can create a new collection with the items removed.

var newList = collection.Where ( item => item != "failed" );

As it is lazily evaluated you are not actually creating two collections in memory, rather a state machine that will enumerate through the non failed items as needed.

Mongus Pong
  • 11,337
  • 9
  • 44
  • 72
0

If the collection is a List or Set, you can use an indexed for loop and perform the deletion.

adarshr
  • 61,315
  • 23
  • 138
  • 167
  • That code gives wierd results: List collection = new List(); collection.Add("one"); collection.Add("second"); collection.Add("third"); for (int i = 0; i < collection.Count; i++) { string v = collection[i]; if (v == "one") collection.Remove(v); } – Chesnokov Yuriy Aug 23 '11 at 11:44
  • In C# you need to have a decrementing for loop not an incrementing one, otherwise items get skipped when you remove (due to indexes changing). See my answer for details. – codeulike Aug 23 '11 at 15:43