Often I have to code a loop that needs a special case for the first item, the code never seems as clear as it should ideally be.
Short of a redesign of the C# language,
You could try:
collection.first(x=>
{
//...
}).rest(x=>
{
//...
}).run();
first / rest would look like:
FirstPart<T> first<T>(this IEnumerable<T> c, Action<T> a)
{
return new FirstPart<T>(c, a);
}
FirstRest rest<T>(this FirstPart<T> fp, Action<T> a)
{
return new FirstRest(fp.Collection, fp.Action, a);
}
You would need to define classed FirstPart and FirstRest. FirstRest would need a run method like so (Collection, FirstAction, and RestAction are properties):
void run()
{
bool first = true;
foreach (var x in Collection)
{
if (first) {
FirstAction(x);
first = false;
}
else {
RestAction(x);
}
}
}
Whilst I wouldn't personally do this, there is another way using enumerators, which alleviates the need for conditional logic. Something like this:
void Main()
{
var numbers = Enumerable.Range(1, 5);
IEnumerator num = numbers.GetEnumerator();
num.MoveNext();
ProcessFirstItem(num.Current); // First item
while(num.MoveNext()) // Iterate rest
{
Console.WriteLine(num.Current);
}
}
void ProcessFirstItem(object first)
{
Console.WriteLine("First is: " + first);
}
Sample output would be:
First is: 1
2
3
4
5
IMHO the most cleanest way is: try to avoid special cases for the first item. That may not work in every situation, of course, but "special cases" may indicate that your program logic is more complex than it needs to be.
By the way, I would not code
if (yyy.Length > 0)
{
for(int i = 1; i <yyy.Length; i++)
{
// ...
}
}
but instead
for(int i = 1; i <yyy.Length; i++)
{
// ...
}
(which is itself a simple example of how to avoid unnecessary dealing with a special case.)
I use the first
variable method all the time and it seems totally normal to me.
If you like that better you can use LINQ First()
and Skip(1)
var firstItem = yyy.First();
// do the whatever on first item
foreach (var y in yyy.Skip(1))
{
// process the rest of the collection
}
The way you wrote it is probably the cleanest way it can be written. After all, there is logic specific to the first element, so it has to be represented somehow.
How about:
using (var erator = enumerable.GetEnumerator())
{
if (erator.MoveNext())
{
ProcessFirst(erator.Current);
//ProcessOther(erator.Current); // Include if appropriate.
while (erator.MoveNext())
ProcessOther(erator.Current);
}
}
You could turn that into an extension if you want:
public static void Do<T>(this IEnumerable<T> source,
Action<T> firstItemAction,
Action<T> otherItemAction)
{
// null-checks omitted
using (var erator = source.GetEnumerator())
{
if (!erator.MoveNext())
return;
firstItemAction(erator.Current);
while (erator.MoveNext())
otherItemAction(erator.Current);
}
}