I'd like to create a copy of an IEnumerator<T>
so that I can restart the enumeration process from a particular location in the collection. Clearly, there is no benefit to doing so for collections that implement IList
, since we can remember the index of interest.
Is there a clever way to accomplish this task using a combination of yield
statements and Linq functions? I could not find a suitable Clone()
method to copy the enumerator, and would like to avoid using Enumerable.Skip()
to reposition a new enumerator to the desired resumption point.
Also, I'd like to keep the solutions as generic as possible, and not have to depend on state from any concrete collections.
IEnumerable. IEnumerable<T> contains a single method that you must implement when implementing this interface; GetEnumerator, which returns an IEnumerator<T> object. The returned IEnumerator<T> provides the ability to iterate through the collection by exposing a Current property.
C# | Clone() Method In C#, Clone() is a String method. It is used to clone the string object, which returns another copy of that data. In other words, it returns a reference to this instance of String. The return value will be only another view of the same data.
IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface. This works for readonly access to a collection that implements that IEnumerable can be used with a foreach statement. IEnumerator has two methods MoveNext and Reset. It also has a property called Current.
IEnumerable is best to query data from in-memory collections like List, Array etc. IEnumerable doesn't support add or remove items from the list. Using IEnumerable we can find out the no of elements in the collection after iterating the collection. IEnumerable supports deferred execution.
The best you could do is write something that keeps a buffer (perhaps a Queue<T>
) of the data consumed from one and not the other (which would get messy/expensive if you advanced one iterator by 1M positions, but left the other alone). I really think you would be better off rethinking the design, though, and just using GetEnumerator()
(i.e. another foreach
) to start again - or buffer the data (if short) in a list/array/whatever.
Nothing elegant built in.
Update: perhaps an interesting alternative design here is "PushLINQ"; rather than clone the iterator, it allows multiple "things" to consume the same data-feed at the same time.
In this example (lifted from Jon's page) we calculate multiple aggregates in parallel:
// Create the data source to watch
DataProducer<Voter> voters = new DataProducer<Voter>();
// Add the aggregators
IFuture<int> total = voters.Count();
IFuture<int> adults = voters.Count(voter => voter.Age >= 18);
IFuture<int> children = voters.Where(voter => voter.Age < 18).Count();
IFuture<int> youngest = voters.Min(voter => voter.Age);
IFuture<int> oldest = voters.Select(voter => voter.Age).Max();
// Push all the data through
voters.ProduceAndEnd(Voter.AllVoters());
// Write out the results
Console.WriteLine("Total voters: {0}", total.Value);
Console.WriteLine("Adult voters: {0}", adults.Value);
Console.WriteLine("Child voters: {0}", children.Value);
Console.WriteLine("Youngest vote age: {0}", youngest.Value);
Console.WriteLine("Oldest voter age: {0}", oldest.Value);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With