Missing SortedList?
Tigraine
Daniel Hoelbling talks about programming and technology

Missing SortedList?

April 10, 2009 by Daniel Hoelbling

I made it a habit to always program towards an Interface if possible. So all my lists in code are of type IList<T> and the IList<T> lacks the .Sort() method of the List<T> class.

Usually this isn’t a problem since there is LinQ’s .OrderBy to save the day. But this time my class is too generic for that so I have to fall back to good old OO principles with comparer classes etc.

Now, my problem is that I need a simple IList that is sorted on insertion. I first thought, no problem I’ll just use the SortedList<Tkey, Tvalue> that’s already in the framework. But there is always a catch: SortedList is more of a dictionary than a list. Duplicate key items aren’t accepted, there is no collision handling. Trying to insert a duplicate key will result in a ArgumentException:

[Fact]
public void SortedList_AcceptsNoDuplicateKeys()
{
    SortedList<int, string> list = new SortedList<int, string>();
    var key = 1;
    list.Add(key, "test");
    Assert.Throws(typeof (ArgumentException), () => list.Add(key, "test2)"));
}

Now, what I need is a real sorted List that allows duplicate values (as would a List.Sort()).

Implementing the IList interface isn’t that hard after all, so I gave it a shot with a SortedKeylessCollection<T> that wraps a real List<T> (to use it’s .Sort(), I know I’m lazy):

public class SortedKeylessCollection<T> : ICollection<T> where T : class
{
    private readonly IComparer<T> comparer;
    private readonly List<T> list = new List<T>();

    public SortedKeylessCollection(IComparer<T> comparer)
    {
        this.comparer = comparer;
    }

    public SortedKeylessCollection() : this(Comparer<T>.Default)
    {
    }

    #region ICollection<T> Members

    public void Add(T item)
    {
        list.Add(item);
        SortList();
    }

    public void Clear()
    {
        list.Clear();
    }

    public bool Contains(T item)
    {
        return list.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        list.CopyTo(array, arrayIndex);
    }

    public bool Remove(T item)
    {
        bool b = list.Remove(item);
        if (b) SortList();
        return b;
    }

    public int Count
    {
        get { return list.Count; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return list.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return list.GetEnumerator();
    }

    #endregion

    public void SortList()
    {
        list.Sort(comparer);
    }
}

You can download the file here: SortedKeylessCollection.cs.

I didn’t call it List but Collection because IList<T> has a defined contract through InsertAt that can’t be fulfilled by a self-sorting list (since the insertion at a position shouldn’t be possible).

Also, as someone at StackOverlow pointed out there are already implementations of such lists like the Wintellect Power Collections for .NET but I didn’t want to bring yet another dependency into my codebase just for one puny little class.