Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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, if you need to do several times around your code?

like image 544
dilbert Avatar asked Jul 01 '11 16:07

dilbert


2 Answers

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.

like image 154
Jon Skeet Avatar answered Nov 10 '22 20:11

Jon Skeet


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.

like image 38
Jim Bolla Avatar answered Nov 10 '22 19:11

Jim Bolla