Most elegant way to process first IEnumerable item differently
What would be the most elegant way to process the first IEnumerable item differently than others, without having to test on each iteration?
With a test on each iteration, it would look like this:
// "first item done" flag
bool firstDone = false;
// items is an IEnumerable<something>
foreach (var item in items)
{
if (!firstDone)
{
// do this only once
ProcessDifferently(item);
firstDone = true;
continue;
}
ProcessNormally(item);
}
If I do this:
ProcessDifferently(items.First());
ProcessNormally(items.Skip(1)); // this calls `items.GetEnumerator` again
it will invoke GetEnumerator
twice, which I would like to avoid (for Linq-to-Sql cases, for example).
How would you do it, i开发者_StackOverflow中文版f you need to do several times around your code?
If I needed to do it in several places, I'd extract a method:
public void Process<T>(IEnumerable<T> source,
Action<T> firstAction,
Action<T> remainderAction)
{
// TODO: Argument validation
using (var iterator = source.GetEnumerator())
{
if (iterator.MoveNext())
{
firstAction(iterator.Current);
}
while (iterator.MoveNext())
{
remainderAction(iterator.Current);
}
}
}
Called as:
Process(items, ProcessDifferently, ProcessNormally);
There are other options too, but it would really depend on the situation.
Here's another way:
private static void Main(string[] args)
{
var testdata = new[] { "a", "b", "c", "d", "e" };
var action = FirstThenRest<string>(
s => Console.WriteLine("First: " + s),
s => Console.WriteLine("Rest: " + s));
foreach (var s in testdata)
action(s);
}
public static Action<T> FirstThenRest<T>(Action<T> first, Action<T> rest)
{
Action<T> closure = t =>
{
first(t);
closure = rest;
};
return t => closure(t);
}
This outputs:
First: a
Rest: b
Rest: c
Rest: d
Rest: e
No conditionals. :D
EDIT: "Head" and "Tail" would probably be better terms but I'm too lazy to go change it now.
You can do it the old fashioned way:
var itemsList = items.ToList();
ProcessDifferently(itemsList[0]);
for(int i=1;i<itemsList.Count;i++)
{
ProcessNormally(itemsList[i]);
}
精彩评论