.Net collections enumeration

shabbir's Avatar author of .Net collections enumeration
This is an article on .Net collections enumeration in C#.
Rated 5.00 By 1 users

Introduction



I happen to edit the collections many times in the foreach loop and run into problems and then each time I got a different solution when going to Google, So first I would try to list each of the solution and then discuss them so that we all can have the best practice in the collection iteration. Please note that I am not saying the one I have mentioned is the best but I found it to be one of the best for my context.

Background



Recently I cam across an exception as Collection was modified; enumeration operation may not execute. and the sample code which can throw such exception is
Code: CSharp
ArrayList list = new ArrayList();
list.Add("123");
list.Add("456");
list.Add("789");
list.Add("741");
list.Add("852");

foreach (string s in list)
{
    if (s == "789")
    {
        list.RemoveAt(list.IndexOf("789"));
    }
}
As a C++ background programmer I normally use to do the same in C++ with arrays and I continued the same in C-Sharp as well but ran into problem with the exception.

Solution 1 : Convert collection to Array



Code: CSharp
foreach (string s in list.ToArray())
{
    if (s == "789")
    {
        list.RemoveAt(list.IndexOf("789"));
    }
}
The method is not very efficient because you are not using the collection but using the arrays and is not good for large collections.

Solution 2 : Use for loop instead foreach.


Code: CSharp
int cnt = list.Count - 1;
for (int i = 0; i < cnt; )
{
    string s = (string)list[i];
    System.Console.WriteLine(s);
    if (s == "789")
    {
        list.RemoveAt(i);
    }
    else
    {
        i++;
    }
}
There are many disadvantages to the above method. One being if you are removing then you should not increment the counter when you are removing or else you will miss the next element after the removed index. Here it would be 741 which is after 789 and the other one being you are always looping through the count -1 initially which is not the case when you add / remove it and so you need to take all the pain to make sure it loops as expected with lots of if's and else's.

Solution 3 : Mark all the element.



Mark all the elements you wish to remove and then iterate through the marked object to remove them.
Code: CSharp
ArrayList indexListToRemove = new ArrayList();
foreach (string s in list)
{
    if (s == "789")
    {
        indexListToRemove.Add(s);
    }
}
foreach (string s in indexListToRemove)
{
    list.Remove(s);
}

Summary



You should avoid changes to collections (in fact most cases you will not even be able to change the collection) using foreach.
venkatesanj@hcl.in's Avatar
Go4Expert Member
Shabbir,

I think you dealt only with list collection. I will try to post my articles on other .net collections.

Regards,
Venkatesan Prabu. J
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Yup
aisha.ansari84's Avatar, Join Date: Feb 2008
Contributor
Quote:
Originally Posted by venkatesanj@hcl.in
Shabbir,

I think you dealt only with list collection. I will try to post my articles on other .net collections.

Regards,
Venkatesan Prabu. J
yes all the others are equivalently important
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Vote for article of the month for Feb 2008