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,
I'd be tempted to use a bit of linq
using System.Linq;
var theCollectionImWorkingOn = ...
var firstItem = theCollectionImWorkingOn.First();
firstItem.DoSomeWork();
foreach(var item in theCollectionImWorkingOn.Skip(1))
{
item.DoSomeOtherWork();
}
In cases like this I would just use a for loop like this:
for(int i = 0; i < yyy.Count; i++){
if(i == 0){
//special logic here
}
}
Using a for loop also would allow you to do something special in other cases like on the last item, on even items in the sequence, ..etc.
My solution:
foreach (var x in yyy.Select((o, i) => new { Object = o, Index = i } )
{
if (x.Index == 0)
{
// First item logic
}
else
{
// Rest of items
}
}
Here's a slightly simpler extension method that does the job. This is a combination of KeithS's solution and my answer to a related Java question:
public static void ForEach<T>(this IEnumerable<T> elements,
Action<T> firstElementAction,
Action<T> standardAction)
{
var currentAction = firstElementAction;
foreach(T element in elements)
{
currentAction(element);
currentAction = standardAction;
}
}
Another option I came up with is
enum ItemType
{
First,
Last,
Normal
}
list.Foreach(T item, ItemType itemType) =>
{
if (itemType == ItemType.First)
{
}
// rest of code
};
Writing the extension method is left as an exercise for the reader… Also should two Boolean flags “IsFirst” and “IsLast” be used instead of ItemType enum, or ItemType be an object that has “IsFirst” and “IsLast” properties?
Both of those are perfectly acceptable algorithms for processing the first element differently, and there really isn't a different way to do it. If this pattern is repeated a lot, you could hide it behind an overload of ForEach():
public static void ForEach<T>(this IEnumerable<T> elements, Action<T> firstElementAction, Action<T> standardAction)
{
var firstItem = true;
foreach(T element in elements)
{
if(firstItem)
{
firstItem = false;
firstElementAction(element)
}
else
standardAction(element)
}
}
...
//usage
yyy.ForEach(t=>(other code when first item), t=>(normal processing code));
Linq makes it a little cleaner:
PerformActionOnFirstElement(yyy.FirstOrDefault());
yyy.Skip(1).ForEach(x=>(normal processing code));