Bookmark and Share

Indexed Sequences

Phil Haack has an interesting article about creating a better Razor foreach loop. It’s a useful solution when one needs to know the current index of an item enumerating a sequence, but I feel the concepts presented can be expanded upon outside of the scope of his article.

In the article, Haack presented a wrapper class called IndexedItem<TModel>. I’m going to change the name of this class to Indexed<T>, expand it slightly, and add a static factory method to take advantage of generic inference.

public class Indexed<T>
{
    public Indexed(int index, T value)
    {
        Index = index;
        Value = value;
    }

    public int Index { get; private set; }
    public T Value { get; private set; }

    public Indexed<U> Select<U>(Func<T, U> selector)
    {
        return Indexed.Create(Index, selector(Value));
    }
}
public static class Indexed
{
    public static Indexed<T> Create<T>(int index, T item)
    {
        return new Indexed<T>(index, item);
    }
}

This wrapper allows us to attach state information to a value. In this case, we’re explicitly declaring that the state information is an Index. The Select method allows us to use LINQ to modify the inner value from one type to another using query expressions. Since the value is exposed, this can be accomplished through other means, but the Select method allows the syntax to be cleaner in certain scenarios.

The next thing to do is allow for the easy projection of any sequence to an indexed sequence. This can be accomplished with an extension method on IEnumerable<T>.

public static IEnumerable<Indexed<T>> ToIndexed<T>(this IEnumerable<T> source)
{
    int index = 0;

    foreach (T t in source)
    {
        yield return Indexed.Create(index, t);
        index++;
    }
}

That’s all there is to it. Here’s a simple test to ensure it works.

[TestMethod]
public void IndexedTest()
{
    var strings = new[] {"One", "Two", "Three", "Four"};            
    var indexed = strings.ToIndexed();            
    var ordered = from s in indexed
                  orderby s.Value
                  select s;

    Assert.AreEqual(0, indexed.First().Index);
    Assert.AreEqual("Four", ordered.First().Value);
    Assert.AreEqual(3, ordered.First().Index);
}

With an indexed sequence, you can change the order yet retain the state for its original index. This can be useful for binding to a sequence without retaining another copy to retain original index information… or worse, junking up business objects with data required only for the presentation layer.

This sample code is available at kodefu.codeplex.com.

blog comments powered by Disqus

KodefuGuru.GetInfo()

Chris Eargle
LinkedIn Twitter Technorati Facebook

Chris Eargle
Telerik Developer Evangelist, C# MVP

JustCode

Telerik .NET Ninja

 

INETA Community Speakers Program

 

MVP - Visual C#

 

Friend of RedGate

World Map

Month List

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.