What does a HashSet Enumerator do?

812 Views Asked by At

I'm not used to write C# code, only Java and Python. Now I found some code example for an algorithm which is only available in C#. There is one structure I don't understand, it is the Enumerator.

HashSet<Node>.Enumerator enumerator = hashSet.GetEnumerator();
enumerator.MoveNext();
Item next = enumerator.Current;

So Item is the data type stored in the HashSet hashSet. Is this equal to a for-loop iterating over a HashSet or how else can that be translated into python or java?

1

There are 1 best solutions below

0
Soner from The Ottoman Empire On

GetEnumerator() methods are presented in some data structures in C# such as List, Set, etc. It enables doing iteration through. Actually, foreach internally makes use of it.


foreach statement is to iterate through the elements of certain data structures. A foreach can be used when all of the following conditions hold:

  • The data structure implements either IEnumerable(which is to satisfy legacy codes before generics) or IEnumerable<T> for some type T.
  • You do not need to know the locations in the data structure of the individual elements.

For example, the string class implements both IEnumerable and IEnumerable<Char>.

The IEnumerable<T> interface implies the data structure requires two methods:

  • public IEnumerator<T> GetEnumerator()
  • IEnumerator IEnumerable.GetEnumerator()

The latter method is required only because IEnumerable<T> is a subtype of IEnumerable, and that interface requires a GetEnumerator method that returns a non-generic IEnumerator. Both of these methods should return the same object; hence, because IEnumerator<T> is also a subtype of IEnumerator, this method can simply call the first method:

System.Collections.IEnumerator IEnumerable.GetEnumerator()
{
    return GetEnumerator();
}

As you can see, the IEnumerable.GetEnumerator() method returns a reference to another interface named System.Collections.IEnumerator. This interface provides the infrastructure to allow the caller to traverse the internal objects contained by the IEnumerable-compatible container:

public interface IEnumerator
{
   bool MoveNext (); // Advance the internal position of the cursor.
   object Current { get;} // Get the current item (read-only property).
   void Reset (); // Reset the cursor before the first member.
}

Let's exemplify it.

public class PowersOfThree : IEnumerable<int>
{      
    public IEnumerator<int> GetEnumerator()
    {
        return new PowersOfThreeEnumerator();
    }       
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }       
}


internal class PowersOfThreeEnumerator : IEnumerator<int>
{
    private int index = 0;

    public int Current
    {
        get { return (int)System.Math.Pow(3, index); }
    }

    object System.Collections.IEnumerator.Current
    {
        get { return Current; }
    }

    public bool MoveNext()
    {
        index++;

        if (index > 10)
            return false;
        else
            return true;
    }

    public void Reset()
    {
        index = 0;
    }

    public void Dispose()
    {
    }
}

public class Test 
{
    public static void Main(string[] str)
    {
        var p2 = new PowersOfThree();
        foreach (int p in p2)
        {
            System.Console.WriteLine(p);
        }
    }
}

Current method returns the same element until MoveNext method is called. The initial index is 0 each MoveNext method increments the index from 1 to 10, inclusively, then it returns false. When the enumerator is at this position, subsequent calls to MoveNext also return false.

Do you see that what happened to Current when MoveNext returned false? Can you set Current to the first element of the collection again? If you don't reinstantiate new enumerator, no.