1. We have moved from vBulletin to XenForo and you are viewing the site in the middle of the move. Though the functional aspect of everything is working fine, we are still working on other changes including the new design on Xenforo.
    Dismiss Notice

.Net collections enumeration

Discussion in 'C#' started by shabbir, Feb 19, 2008.

  1. shabbir

    shabbir Administrator Staff Member

    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:
    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:
    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:
    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:
    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.
     
  2. venkatesanj@hcl.in

    venkatesanj@hcl.in New 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
     
  3. shabbir

    shabbir Administrator Staff Member

  4. shabbir

    shabbir Administrator Staff Member

  5. aisha.ansari84

    aisha.ansari84 New Member

    yes all the others are equivalently important
     
  6. shabbir

    shabbir Administrator Staff Member

Share This Page