Sort a list alphabetically

Mariko picture Mariko · Aug 6, 2011 · Viewed 209.7k times · Source

I have the following class:

class Detail
{
    public Detail()
    {
        _details = new List<string>();
    }
    public IList<string> Details { get { return _details; } }
    private readonly List<string> _details;
}

Currently I sort the class randomly using the following:

void ShuffleGenericList<T>(IList<T> list)
{
    //generate a Random instance
    var rnd = new Random();
    //get the count of items in the list
    var i = list.Count();
    //do we have a reference type or a value type
    T val = default(T);

    //we will loop through the list backwards
    while (i >= 1)
    {
        //decrement our counter
        i--;
        //grab the next random item from the list
        var nextIndex = rnd.Next(i, list.Count());
        val = list[nextIndex];
        //start swapping values
        list[nextIndex] = list[i];
        list[i] = val;
    }
}

What I would like to do is to sort the contents of details in alphabetic order.

So for example if the contents look like this:

[0] a
[1] d
[2] b

I want to be able to run this method and have them sorted into:

[0] a
[1] b
[2] d

Does anyone know of a simple way to do this? Note that the lists usually have less than ten entries in them. Can I do this with LINQ? Sorry but I am not very familiar with LINQ I have just heard a suggestion that I could use that.

Answer

Jon Skeet picture Jon Skeet · Aug 6, 2011

You can sort a list in-place just by calling List<T>.Sort:

list.Sort();

That will use the natural ordering of elements, which is fine in your case.

EDIT: Note that in your code, you'd need

_details.Sort();

as the Sort method is only defined in List<T>, not IList<T>. If you need to sort it from the outside where you don't have access to it as a List<T> (you shouldn't cast it as the List<T> part is an implementation detail) you'll need to do a bit more work.

I don't know of any IList<T>-based in-place sorts in .NET, which is slightly odd now I come to think of it. IList<T> provides everything you'd need, so it could be written as an extension method. There are lots of quicksort implementations around if you want to use one of those.

If you don't care about a bit of inefficiency, you could always use:

public void Sort<T>(IList<T> list)
{
    List<T> tmp = new List<T>(list);
    tmp.Sort();
    for (int i = 0; i < tmp.Count; i++)
    {
        list[i] = tmp[i];
    }
}

In other words, copy, sort in place, then copy the sorted list back.


You can use LINQ to create a new list which contains the original values but sorted:

var sortedList = list.OrderBy(x => x).ToList();

It depends which behaviour you want. Note that your shuffle method isn't really ideal:

  • Creating a new Random within the method runs into some of the problems shown here
  • You can declare val inside the loop - you're not using that default value
  • It's more idiomatic to use the Count property when you know you're working with an IList<T>
  • To my mind, a for loop is simpler to understand than traversing the list backwards with a while loop

There are other implementations of shuffling with Fisher-Yates on Stack Overflow - search and you'll find one pretty quickly.