Enumerating with extra info in the Miscellaneous Utility Library

I don't know about you, but I've frequently iterated over a collection and manually kept track of whether I'm on the first or the last element, usually in order to output some sort of separator between items or something similar. With a normal foreach statement directly over the collection in question, you have to remember whether or not you're on the first element and there's no simple way of telling whether or not you're on the last element. Enter SmartEnumerable<T>.

Using any implementation of IEnumerable<T> you can construct an instance of SmartEnumerable<T>. When you call GetEnumerator() on the instance (as foreach does automatically) you get an IEnumerator<SmartEnumerable<T>.Entry>. The Entry type has four properties: IsFirst, IsLast, Index and Value. The meanings are mostly self-explanatory. The Index property returns 0 for the first element returned, 1 for the next etc. For some collections this won't represent an indexable value, but for many (arrays and lists in particular) it does, and can be quite handy. The program below iterates over a list of strings, indicating the first and last elements in the list, along with the index.

using System;
using System.Collections.Generic;

using MiscUtil.Collections;

class Example
{
    static void Main(string[] args)
    {
        List<string> list = new List<string>();
        list.Add("a");
        list.Add("b");
        list.Add("c");
        list.Add("d");
        list.Add("e");
        
        foreach (SmartEnumerable<string>.Entry entry in
                 new SmartEnumerable<string>(list))
        {
            Console.WriteLine ("{0,-7} {1} ({2}) {3}",
                               entry.IsLast  ? "Last ->" : "",
                               entry.Value,
                               entry.Index,
                               entry.IsFirst ? "<- First" : "");
        }
    }
}

The output is as follows:

        a (0) <- First
        b (1)
        c (2)
        d (3)
Last -> e (4)

It's not that this is really, really hard to keep track of manually - but it's yet another piece of code which comes up time and time again. Hope you find it as useful as I'm sure I will.

Update (Feb 26th 2009)

There are now two additional ways to create a SmartEnumerable<T>. You can use the nongeneric static class SmartEnumerable and its Create method, or the extension method in MiscUtil.Collections.Extensions:

// Old way
foreach (SmartEnumerable<string>.Entry entry in
                 new SmartEnumerable<string>(list))

// Better way
foreach (SmartEnumerable<string>.Entry entry in
                SmartEnumerable.Create(list))

// Best way (C# 3.0)
foreach (var entry in list.AsSmartEnumerable())

Back to the main MiscUtil page.