484

I'm using C# on Framework 3.5. I'm looking to quickly sort a Generic List<T>. For the sake of this example, let's say I have a List of a Person type with a property of lastname. How would I sort this List using a lambda expression?

List<Person> people = PopulateList();
people.OrderBy(???? => ?????)
SaaS Developer
  • 9,835
  • 7
  • 34
  • 45

10 Answers10

744

If you mean an in-place sort (i.e. the list is updated):

people.Sort((x, y) => string.Compare(x.LastName, y.LastName));

If you mean a new list:

var newList = people.OrderBy(x=>x.LastName).ToList(); // ToList optional
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 2
    I believe that first one wants to be people.Sort((x, y) => string.Compare(x.LastName, y.LastName) < 0); – James Curran Oct 09 '08 at 16:56
  • 36
    @James: I wouldn't think so. Comparison returns int, not bool. – Jon Skeet Oct 09 '08 at 16:59
  • 2
    I wonder if you want to OrderBy Firstname and Lastname... what should you write? – balexandre Apr 16 '09 at 07:03
  • 67
    var newList = people.OrderBy(x=>x.FirstName).ThenBy(x=>x.LastName).ToList(); – Marc Gravell Apr 16 '09 at 07:36
  • 2
    How to sort if the data type in int. int.Compare? –  Feb 16 '14 at 18:06
  • 2
    @Faraz just use x.CompareTo(y). That is trickier for strings because a: nulls, and b: different ways if sorting strings (case sensitivity, culture, etc) – Marc Gravell Feb 16 '14 at 18:07
  • 1
    people.Sort((x, y) => string.Compare(x.LastName, y.LastName)); If here datatype is int instead of string... Then how do I sort? people.Sort((x, y) => int.Compare(x.price, y.price));? –  Feb 16 '14 at 18:11
  • 4
    @Faraz (x,y)=>x.price.CompareTo(y.price) – Marc Gravell Feb 16 '14 at 18:18
  • `Cannot convert lambda expression to type 'System.Generic.Collections.IComparer' because it is not a delegate type` is the error I get on the first one. – vapcguy Mar 20 '15 at 00:39
107

Do you need the list to be sorted in place, or just an ordered sequence of the contents of the list? The latter is easier:

var peopleInOrder = people.OrderBy(person => person.LastName);

To sort in place, you'd need an IComparer<Person> or a Comparison<Person>. For that, you may wish to consider ProjectionComparer in MiscUtil.

(I know I keep bringing MiscUtil up - it just keeps being relevant...)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
27
people.OrderBy(person => person.lastname).ToList();
bluish
  • 26,356
  • 27
  • 122
  • 180
Danimal
  • 7,672
  • 8
  • 47
  • 57
  • 18
    Well, that still doesn't capture the result - you'd need a "List people = " on the left hand side... – Marc Gravell Oct 09 '08 at 17:10
  • 9
    This answer demonstates most common error when using LINQ - methods like `OrderBy` *do not* modify list, but rather return new "collection" (usually lazy `IEnumerable`) that need to be assigned to something. – Alexei Levenkov Aug 31 '15 at 20:41
  • 2
    @AlexeiLevenkov how do you know this is the most common error when using LINQ? – tymtam Mar 02 '16 at 05:58
25

you can use linq :) using :

System.linq;
var newList = people.OrderBy(x=>x.Name).ToList();
Sparkup
  • 3,686
  • 2
  • 36
  • 50
vampire203
  • 341
  • 3
  • 3
15
private void SortGridGenerico< T >(
          ref List< T > lista       
    , SortDirection sort
    , string propriedadeAOrdenar)
{

    if (!string.IsNullOrEmpty(propriedadeAOrdenar)
    && lista != null
    && lista.Count > 0)
    {

        Type t = lista[0].GetType();

        if (sort == SortDirection.Ascending)
        {

            lista = lista.OrderBy(
                a => t.InvokeMember(
                    propriedadeAOrdenar
                    , System.Reflection.BindingFlags.GetProperty
                    , null
                    , a
                    , null
                )
            ).ToList();
        }
        else
        {
            lista = lista.OrderByDescending(
                a => t.InvokeMember(
                    propriedadeAOrdenar
                    , System.Reflection.BindingFlags.GetProperty
                    , null
                    , a
                    , null
                )
            ).ToList();
        }
    }
}
bluish
  • 26,356
  • 27
  • 122
  • 180
Bruno
  • 151
  • 1
  • 3
6

You can use this code snippet:

var New1 = EmpList.OrderBy(z => z.Age).ToList();

where New1 is a List<Employee>.

EmpList is variable of a List<Employee>.

z is a variable of Employee type.

jalgames
  • 781
  • 4
  • 23
6

You can also use

model.People = model.People.OrderBy(x => x.Name).ToList();
rosselder83
  • 102
  • 1
  • 2
  • 4
    While this code sample may answer the question, it lacks explanation. As it stands now, it adds no value, and stands the change of being downvoted / deleted. Please add some explanation what is does and why it is a solution for the problem of the OP. – oɔɯǝɹ Feb 02 '15 at 10:10
6

for me this useful dummy guide - Sorting in Generic List - worked. it helps you to understand 4 ways(overloads) to do this job with very complete and clear explanations and simple examples

  • List.Sort ()
  • List.Sort (Generic Comparison)
  • List.Sort (Generic IComparer)
  • List.Sort (Int32, Int32, Generic IComparer)
Iman
  • 17,932
  • 6
  • 80
  • 90
2

This is a generic sorter. Called with the switch below.

dvm.PagePermissions is a property on my ViewModel of type List T in this case T is a EF6 model class called page_permission.

dvm.UserNameSortDir is a string property on the viewmodel that holds the next sort direction. The one that is actaully used in the view.

switch (sortColumn)
{
    case "user_name":
        dvm.PagePermissions = Sort(dvm.PagePermissions, p => p.user_name, ref sortDir);
        dvm.UserNameSortDir = sortDir;
        break;
    case "role_name":
        dvm.PagePermissions = Sort(dvm.PagePermissions, p => p.role_name, ref sortDir);
        dvm.RoleNameSortDir = sortDir;
        break;
    case "page_name":
        dvm.PagePermissions = Sort(dvm.PagePermissions, p => p.page_name, ref sortDir);
        dvm.PageNameSortDir = sortDir;
        break;
}                 


public List<T> Sort<T,TKey>(List<T> list, Func<T, TKey> sorter, ref string direction)
    {
        if (direction == "asc")
        {
            list = list.OrderBy(sorter).ToList();
            direction = "desc";
        }
        else
        {
            list = list.OrderByDescending(sorter).ToList();
            direction = "asc";
        }
        return list;
    }
jalgames
  • 781
  • 4
  • 23
howserss
  • 1,139
  • 1
  • 8
  • 12
  • 1
    I think that this is way too complicated. As you can see in the other answers, it can all be done in one single line (it doesn't necessarily mean that doing it in a single line is good, but I don't get the advantage of doing it like this) – jalgames Jul 19 '14 at 21:29
  • This is for multi column sorting using AngularJS. It is essentially the single line sorting but it also sets the sort diretion variable. Its really not that complex if you look at it closely. I guess the Sort function is a little intimidating with all the generic stuff but if I took that definition out it is a 1 line Sort call. – howserss Aug 08 '14 at 14:23
  • Too complicated for what the Op requested. It is a good solution for a different problem though. – rollsch Jul 26 '17 at 00:19
0

In .NET 7 preview you can use the simplified ordering of System.Linq. It also has some performance improvements.

var sorted = people.Order();

Also, be aware that the Sort method has a better performance in most cases because you don't allocate a new list.

Misha Zaslavsky
  • 8,414
  • 11
  • 70
  • 116