Enumerator vs for loop


#1

Hi,

What is the difference using enumerator and normal for loop in C#?
Are there any pros and cons?

For instance there is an example with ngons, and I am trying to understand why there is an enumerator here:

            using (HashSet<int> nums = new HashSet<int>())
            {
                enumerator = mesh.Ngons.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    uint[] numArray = enumerator.Current.FaceIndexList();
                    for (int i = 0; i < (int)numArray.Length; i ++)
                    {
                        uint num = numArray[i];
                        nums.Add(Convert.ToInt32(num));
                    }
                }
            }

(Menno Deij - van Rijswijk) #2

There are actually more types of looping: a classic for-loop, a foreach loop and the explicit use of the enumerator (and also the while and do-while loops). In fact, the foreach and enumerator use are the same: when you write a foreach loop in code, the compiler will use an enumerator “under the hood” for you.

A for-loop is slightly faster (but only noticeable for millions of elements), because it takes less or less complex instructions to increment the index and retrieve the indexed item then it takes to call .MoveNext() and .Current.

A for loop can only be used if there is an index available. I don’t know about the Ngons member, but it may be that it has no indexing. In that case, using a foreach loop (or as you see the explicit use of an enumerator) is the only possibility.


#3

Thanks, I have one more question. I know it is more stackoverflow question.

Some of collections can be iterated in for loop using .ElementAt(i).

What is more efficient
foreach loop or for loop with ElementAt(i).

Probably it also depends on situation, where it is more comfortable to use.


(David Rutten) #4

foreach should always be your first choice, unless you have access to an index and need that index, or unless performance is of paramount importance.

The only conceivable time you’d want to use the enumerators directly is if you want to iterate over two or more index-less collections at the same time. And even then there’s LINQ statements (such as Zip()) that allow for nicer looking code.


#5

Hey Petras,

I’d also avoid ElementAt where possible since its time complexity varies between collection types. For example, calling on a List is O(1) but calling on a LinkedList is O(n). So while both can be enumerated in linear time with a foreach loop, using a for loop with ElementAt will be quadratic for the latter.


#6

Hi Dave,

How would a proper iteration would be when iterating over HashSet and Array in one time?
( I know that it is not good to loop through HashSet as it does not have fixed indexing that can change, but still).

The more specific situation is this both collections are equal in length:

        HashSet<int> e = mesh.GetAllNGonEdges(b);
        Line[] l = mesh.GetAllNGonEdgesLines(e);

I have used “for” loop and iterating over array l[i] and hashset e.ElementAt(i) in one go.

What is the proper way of iterating in this situaton?

Thanks,
Petras


#7

Here’s a few ways you could go about it in order of (personal) preference.


    HashSet edges = null;
    Line[] lines = null;

    // using ValueTuple (C# 7)
    foreach(var pair in edges.Zip(lines, (e, ln) => (e, ln)))
    {
        int e = pair.Item1;
        Line ln = pair.Item2;
    }

    // using Tuple
    foreach (var pair in edges.Zip(lines, (e, ln) => Tuple.Create(e,ln)))
    {
        int e = pair.Item1;
        Line ln = pair.Item2;
    }

    // uglier alternative
    var itr = edges.GetEnumerator();
    foreach (var ln in lines)
    {
        itr.MoveNext();
        var e = itr.Current;
    }

#8

Thanks:) Zip seems to be a very nice helper, and C# 7 seems to be much cleaner in writing , also with out keyword in one line, lot of new goodies.