|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionI like to use the enumerators features of .Net framework, specially the
I have created a helper class that enhance enumeration of existing collection enumerators. Since there are lots of collections in .Net's The helper classThe helper class wraps a set of static methods that can be used without instantiating an object. Them are defined in the namespace System.Collections
{
public class Enumerators
{
public static IEnumerable CircularEnum(IEnumerable _enumerator) ...
public static IEnumerable ReverseEnum(IEnumerable _enumerator) ...
public static IEnumerable SteppedEnum(IEnumerable _enumerator, int _step) ...
public static IEnumerable ConstrainedEnum(IEnumerable _enumerator, int _start) ...
public static IEnumerable ConstrainedEnum(IEnumerable _enumerator, int _start, int _count) ...
}
}
The sample collectionAs can be read in the previous code, all enumerator methods will receive another enumerator object (any derived from SortedList
Circular enumeratorThe simplest enumerator is the circular, processed by the public static IEnumerable CircularEnum(IEnumerable _enumerator)
{
while (true)
{
IEnumerator enu = _enumerator.GetEnumerator();
while (enu.MoveNext())
{
yield return enu.Current;
}
}
}
There should be some kind of control to stop the infinite loop under certain condition. In the sample code, there is a constant defined as: const int max = 15; // Max number of iterations to stop circular enumerator
Having defined a stop behaviour, the circular enumerator can be used as: Console.WriteLine("Dictionary circular enumeration:");
int i = 0;
foreach (KeyValuePair<int, string> pair in Enumerators.CircularEnum(list))
{
Console.WriteLine(" " + pair.ToString());
if (++i >= max)
break; // stop circular enumerator, will be infinite if not
}
Console.WriteLine(" (stopped)\r\n");
OUTPUT:
Dictionary circular enumeration:
[1, one]
[2, two]
[3, three]
[4, four]
[5, five]
[6, six]
[7, seven]
[8, eight]
[9, nine]
[10, ten]
[1, one]
[2, two]
[3, three]
[4, four]
[5, five]
(stopped)
Constrained enumeratorSometimes it is needed to traverse just a portion of an enumerated collection, something like the public static IEnumerable ConstrainedEnum(IEnumerable _enumerator, int _start)
{
if (_start < 0)
throw new ArgumentException("Invalid step value, must be positive or zero.");
IEnumerator enu = _enumerator.GetEnumerator();
while (enu.MoveNext())
{
if (--_start < 0)
yield return enu.Current;
}
}
public static IEnumerable ConstrainedEnum(IEnumerable _enumerator, int _start, int _count)
{
if (_start < 0)
throw new ArgumentException("Invalid step value, must be positive or zero.");
if (_count < 0)
throw new ArgumentException("Invalid count value, must be positive or zero.");
if (_count > 0)
{
IEnumerator enu = _enumerator.GetEnumerator();
if (enu.MoveNext())
{
while (--_start > 0)
{
if (!enu.MoveNext())
break;
}
if (_start <= 0)
{
while (--_count >= 0)
{
if (enu.MoveNext())
yield return enu.Current;
else
break;
}
}
}
}
}
The sample code uses the second version of the Console.WriteLine("Constrained enumeration (2,5):");
foreach (KeyValuePair
Stepped enumeratorThis method ( public static IEnumerable SteppedEnum(IEnumerable _enumerator, int _step)
{
if (_step < 1)
throw new ArgumentException("Invalid step value, must be greater than zero.");
IEnumerator enu = _enumerator.GetEnumerator();
while (enu.MoveNext())
{
yield return enu.Current;
for (int i = _step; i > 1; i--)
if (!enu.MoveNext())
break;
}
}
The sample code will enumerate a collection skipping two elements in each iteration: Console.WriteLine("Stepped enumeration (3):");
foreach (int value in Enumerators.SteppedEnum(list.Keys, 3))
{
Console.WriteLine(" " + value.ToString());
}
Console.WriteLine(" (finished)\r\n");
OUTPUT:
Stepped enumeration (3):
1
4
7
10
(finished)
Bonus: Reverse enumerator.Net enumerators (derived from public static IEnumerable ReverseEnum(IEnumerable _enumerator)
{
System.Reflection.PropertyInfo countprop = _enumerator.GetType().GetProperty("Count", typeof(int));
if (countprop == null)
throw new ArgumentException("Collection doesn't have a Count property, cannot enumerate.");
int count = (int)countprop.GetValue(_enumerator, null);
if (count<1)
throw new ArgumentException("Collection is empty");
System.Reflection.PropertyInfo indexer = _enumerator.GetType().GetProperty("Item", new Type[] { typeof(int) });
if (indexer == null)
throw new ArgumentException("Collection doesn't have a proper indexed property, cannot enumerate.");
for (int i = count - 1; i >= 0; i--)
yield return indexer.GetValue(_enumerator, new object[] { i });
}
For this method, the sample code will traverse the Values collection only, not the key/value pairs: Console.WriteLine("Reverse enumeration:");
foreach (string value in Enumerators.ReverseEnum(list.Values))
{
Console.WriteLine(" " + value.ToString());
}
Console.WriteLine(" (finished)\r\n");
OUTPUT:
Reverse enumeration:
ten
nine
eight
seven
six
five
four
three
two
one
(finished)
Combining enumeratorsThe enumerators can be combined (chained) in any way, but you should be aware about the effect produced. It is not the same a circular-stepped enumerator than a stepped-circular enumerator. The sample code combines all the four kinds of enumerators in a single Console.WriteLine("Combined Constrained(2,6)-Stepped(3)-Circular-Reverse enumeration:");
i = 0;
foreach (int value in Enumerators.ConstrainedEnum(Enumerators.SteppedEnum(Enumerators.CircularEnum(Enumerators.ReverseEnum(list.Keys)), 3), 2, 6))
{
Console.WriteLine(" " + value.ToString());
if (++i >= max * 2)
break; // stop circular enumerator, will be infinite if not
}
Console.WriteLine(" (finished)");
OUTPUT:
Combined Constrained(2,6)-Stepped(3)-Circular-Reverse enumeration:
4
1
8
5
2
9
(finished)
Using the source codeThe provided source code is built using Visual C# 2008, so trying to compile the solution in a lower version may not be possible. Anyway, you can simply create a new console project and attach the History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||