Enumerating the Enumerable C# with Example



Enumerating the Enumerable C# with Example

The IEnumerable interface is the base interface for all generic enumerators and is a quintessential part of 
understanding LINQ. At its core, it represents the sequence. 
This underlying interface is inherited by all of the generic collections, such as Collection, Array, List, 
Dictionary Class, and HashSet. 
In addition to representing the sequence, any class that inherits from IEnumerable must provide an 
IEnumerator. The enumerator exposes the iterator for the enumerable, and these two interconnected 
interfaces and ideas are the source of the saying "enumerate the enumerable". 
"Enumerating the enumerable" is an important phrase. The enumerable is simply a structure for how to iterate, it 
does not hold any materialized objects. For example, when sorting, an enumerable may hold the criteria of the field 
to sort, but using .OrderBy() in itself will return an IEnumerable which only knows how to sort. Using a call 
which will materialize the objects, as in iterate the set, is known as enumerating (for example .ToList()). The 
enumeration process will use the the enumerable definition of how in order to move through the series and return 
the relevant objects (in order, filtered, projected, etc.). 
Only once the enumerable has been enumerated does it cause the materialization of the objects, which is when 
metrics like time complexity (how long it should take related to series size) and spacial complexity (how much space 
it should use related to series size) can be measured. 
Creating your own class that inherits from IEnumerable can be a little complicated depending on the underlying 
series that needs to be enumerable. In general it is best to use one of the existing generic collections. That said, it is 
also possible to inherit from the IEnumerable interface without having a defined array as the underlying 
structure. 
For example, using the Fibonacci series as the underlying sequence. Note that the call to Where simply builds an 
IEnumerable, and it is not until a call to enumerate that enumerable is made that any of the values are materialized. 
void Main() 
{ 
Fibonacci Fibo = new Fibonacci(); 
IEnumerable quadrillionplus = Fibo.Where(i => i > 1000000000000); 
Console.WriteLine("Enumerable built"); 
Console.WriteLine(quadrillionplus.Take(2).Sum()); 
Console.WriteLine(quadrillionplus.Skip(2).First()); 
IEnumerable fibMod612 = Fibo.OrderBy(i => i % 612); 
Console.WriteLine("Enumerable built"); 
Console.WriteLine(fibMod612.First());//smallest divisible by 612 
} 
public class Fibonacci : IEnumerable 
{ 
private int max = 90; 
//Enumerator called typically from foreach 
public IEnumerator GetEnumerator() { 
long n0 = 1; 
long n1 = 1; 
Console.WriteLine("Enumerating the Enumerable"); 
for(int i = 0; i < max; i++){ 
yield return n0+n1; 
n1 += n0; 
n0 = n1-n0; 
 

} 
} 
//Enumerable called typically from linq 
IEnumerator IEnumerable.GetEnumerator() { 
long n0 = 1; 
long n1 = 1; 
Console.WriteLine("Enumerating the Enumerable"); 
for(int i = 0; i < max; i++){ 
yield return n0+n1; 
n1 += n0; 
n0 = n1-n0; 
} 
} 
} 
Output 
Enumerable built 
Enumerating the Enumerable 
4052739537881 
Enumerating the Enumerable 
4052739537881 
Enumerable built 
Enumerating the Enumerable 
14930352 
The strength in the second set (the fibMod612) is that even though we made the call to order our entire set of 
Fibonacci numbers, since only one value was taken using .First() the time complexity was O(n) as only 1 value 
needed to be compared during the ordering algorithm's execution. This is because our enumerator only asked for 1 
value, and so the entire enumerable did not have to be materialized. Had we used .Take(5) instead of .First() 
the enumerator would have asked for 5 values, and at most 5 values would need to be materialized. Compared to 
needing to order an entire set and then take the first 5 values, the principle of saves a lot of execution time and 
space. 

0 Comment's

Comment Form

Submit Comment