106

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.

Ry-
  • 218,210
  • 55
  • 464
  • 476
Mariko
  • 1,075
  • 2
  • 7
  • 4

5 Answers5

184

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.

Pang
  • 9,564
  • 146
  • 81
  • 122
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • So if I wanted to sort the list you create above then would I just need to say: sortedList.Sort ? – Mariko Aug 06 '11 at 07:09
  • I tried the Sort but can't get that to work.- My list looks like this: IList nD. I tried nD.Sort() but it says: Can't resolve symbol 'Sort'. – Mariko Aug 06 '11 at 07:20
  • @Mariko: Use `_details.Sort()` instead - as `_details` is declared as a `List` rather than `IList`. `Sort` is only declared on `List`, not `IList`. – Jon Skeet Aug 06 '11 at 07:34
35

There are two ways:

Without LINQ: yourList.Sort();

With LINQ: yourList.OrderBy(x => x).ToList()

You will find more information in: https://www.dotnetperls.com/sort

Damiox
  • 622
  • 4
  • 12
  • @Dminox - My list looks like this: IList nD. I tried nD.Sort() but it says: Can't resolve symbol 'Sort'. – Mariko Aug 06 '11 at 07:17
  • 1
    @Mariko `Sort()` is a member of `List` *not* `IList`. You might consider switching to the former (unless you expect to be working with different `IList` implementations.) – dlev Aug 06 '11 at 07:19
28

Another way

_details.Sort((s1, s2) => s1.CompareTo(s2)); 
lahsrah
  • 9,013
  • 5
  • 37
  • 67
  • 10
    This one has the advantage of adapting to **sorting any object by one of it's properties**. – MGOwen Nov 01 '12 at 06:11
  • +1 I combined this with [another answer](https://stackoverflow.com/a/32578647/1836461) to unit/integration test sorting order of a string. – computercarguy Feb 23 '23 at 18:20
13

You should be able to use OrderBy in LINQ...

var sortedItems = myList.OrderBy(s => s);
Quintin Robinson
  • 81,193
  • 14
  • 123
  • 132
1

What is wrong with List<T>.Sort()?

https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.sort#overloads

Pang
  • 9,564
  • 146
  • 81
  • 122
Oleg Dudnyk
  • 1,009
  • 1
  • 10
  • 22
  • @goril - I would like to use this but I get an error. This is what I added to the other comment. Hope you can help - My list looks like this: IList nD. I tried nD.Sort() but it says: Can't resolve symbol 'Sort'. – Mariko Aug 06 '11 at 07:18
  • 1
    @Mariko: you use interface IList which does not contain Sort method. Sort List variable directly. In other words you can sort `_details` from your example but not `Details` – Oleg Dudnyk Aug 06 '11 at 07:31