Simon Woods Simon Woods - 1 month ago 23
C# Question

Linq - lookahead Iteration

I am iterating thru a collection using a visitor-type pattern and need to access the current and next item in the list. At the moment I am doing it via an extension method like this

public void Visit<TItem>(this IEnumerable<TItem> theList, Action<TItem, TItem> visitor)
{
for (i = 0; i <= theList.Count - 1; i++) {
if (i == theList.Count - 1) {
visitor(theList(i), null);
} else {
visitor(theList(i), theList(i + 1));
}
}
}


I was wondering whether there are other/better/more elegant ways to achieve this? At the moment I think I only need to have access to the current and next items in the list, but I'm wondering whether I may encounter situations where I may need to lookahead the next 'n' items, for example.

Answer

Assuming you're using .NET 4, you can use Zip to accomplish the same thing:

var query = original.Zip(original.Skip(1),
                         (current, next) => new { current, next });

This will iterate over the sequence twice though. A nicer alternative to your current extension method (which I don't believe will work, btw, as IEnumerable doesn't have a Count property, and you're trying to call theList as a method as well...) would be something like:

public static void Visit<TItem>(this IEnumerable<TItem> theList,
                         Action<TItem, TItem> visitor)
{
    TItem prev = default(TItem);
    using (var iterator = theList.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            return;
        }
        prev = iterator.Current;
        while (iterator.MoveNext())
        {
            TItem current = iterator.Current;
            visitor(prev, current);
            prev = current;
        }
    }
    visitor(prev, default(TItem)); // Are you sure you want this?
}

A more general lookahead is trickier, to be honest... you'd want some sort of circular buffer, I suspect... probably a custom collection.

Comments