Search code examples
c#.netienumerablecontrol-flow

IEnumerable foreach, do something different for the last element


I have an IEnumerable<T>. I want to do one thing for each item of the collection, except the last item, to which I want to do something else. How can I code this neatly? In Pseudocode

foreach (var item in collection)
{
    if ( final )
    {
        g(item)
    }
    else
    {
        f(item)
    }
}

So if my IEnumerable were Enumerable.Range(1,4) I'd do f(1) f(2) f(3) g(4). NB. If my IEnumerable happens to be length 1, I want g(1).

My IEnumerable happens to be kind of crappy, making Count() as expensive as looping over the whole thing.


Solution

  • Since you mention IEnumerable[<T>] (not IList[<T>] etc), we can't rely on counts etc: so I would be tempted to unroll the foreach:

    using(var iter = source.GetEnumerator()) {
        if(iter.MoveNext()) {
            T last = iter.Current;
            while(iter.MoveNext()) {
                // here, "last" is a non-final value; do something with "last"
                last = iter.Current;
            }
            // here, "last" is the FINAL one; do something else with "last"
        }
    }
    

    Note the above is technically only valid for IEnuemerable<T>; for non-generic, you'd need:

    var iter = source.GetEnumerator();
    using(iter as IDisposable) {
        if(iter.MoveNext()) {
            SomeType last = (SomeType) iter.Current;
            while(iter.MoveNext()) {
                // here, "last" is a non-final value; do something with "last"
                last = (SomeType) iter.Current;
            }
            // here, "last" is the FINAL one; do something else with "last"
        }
    }