By Shyju


2010-07-22 13:13:25 8 Comments

I have a class called Order which has properties such as OrderId, OrderDate, Quantity, and Total. I have a list of this Order class:

List<Order> objListOrder = new List<Order>();
GetOrderList(objListOrder); // fill list of orders

Now I want to sort the list based on one property of the Order object, for example I need to sort it by the order date or order id.

How can i do this in C#?

19 comments

@LukeH 2010-07-22 13:23:29

If you need to sort the list in-place then you can use the Sort method, passing a Comparison<T> delegate:

objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate));

If you prefer to create a new, sorted sequence rather than sort in-place then you can use LINQ's OrderBy method, as mentioned in the other answers.

@Jon Schneider 2015-03-30 15:04:39

If your date fields are of type Nullable DateTime (i.e. DateTime?), and you get a compile error like "Cannot convert lambda expression to type 'System.Collections.Generic.IComparer<...>' because it is not a delegate type", the real problem may be that there's no CompareTo method on nullable type DateTime?. If you're sure the object won't be null, you can cast it to plain DateTime to fix the problem.

@Jonathan Wood 2015-12-30 17:11:54

Yes, this is the "correct" answer and should be much more efficient than creating a new IEnumerable and then converting it to a new list.

@Jeppe Stig Nielsen 2016-06-09 08:13:37

Of course, if you need descending sort, swap x and y on the right-hand side of the arrow =>.

@Mitchell Currie 2016-08-09 01:09:50

The real answer that actually sorts the list in-place

@Cdaragorn 2016-12-14 20:58:09

@PimBrouwers This is the better option period. Even if the amount of memory you are using is not an issue, this solution avoids unnecessary memory allocation which is EXTREMELY expensive. This option is just as simple codewise and an order of magnitude faster.

@Jeppe Stig Nielsen 2017-01-30 11:39:40

@JonSchneider For Nullable<> (take DateTime? as the example) you can use .Sort((x, y) => Nullable.Compare(x.OrderDate, y.OrderDate)) which will treat null as preceding all non-null values. It is exactly the same as .Sort((x, y) => Comparer<DateTime?>.Default.Compare(x.OrderDate, y.OrderDate).

@Luke Dupin 2018-09-05 23:05:05

Insanely nit-picky, but using a,b instead of x,y is more common for sorting.

@Arpit Patel 2018-11-22 23:43:51

You are the best @LukeDupin

@Unknown 2019-08-24 07:53:20

Quick and clean! thank you so much

@PSK 2010-07-22 13:23:34

Simplest way to order a list is to use OrderBy

 List<Order> objListOrder = 
    source.OrderBy(order => order.OrderDate).ToList();

If you want to order by multiple columns like following SQL Query.

ORDER BY OrderDate, OrderId

To achieve this you can use ThenBy like following.

  List<Order> objListOrder = 
    source.OrderBy(order => order.OrderDate).ThenBy(order => order.OrderId).ToList();

@Jevgenij Kononov 2017-05-31 08:26:36

var obj = db.Items.Where...

var orderBYItemId = obj.OrderByDescending(c => Convert.ToInt32(c.ID));

@radarbob 2014-10-16 14:03:50

A Classical Object Oriented Solution

First I must genuflect to the awesomeness of LINQ.... Now that we've got that out of the way

A variation on JimmyHoffa answer. With generics the CompareTo parameter becomes type safe.

public class Order : IComparable<Order> {

    public int CompareTo( Order that ) {
        if ( that == null ) return 1;
        if ( this.OrderDate > that.OrderDate) return 1;
        if ( this.OrderDate < that.OrderDate) return -1;
        return 0;
    }
}

// in the client code
// assume myOrders is a populated List<Order>
myOrders.Sort(); 

This default sortability is re-usable of course. That is each client does not have to redundantly re-write the sorting logic. Swapping the "1" and "-1" (or the logic operators, your choice) reverses the sort order.

@Loc Huynh 2017-06-22 20:55:48

Simple approach for sorting objects in a List. But I do not understand why you return 1 if (that == null)?

@radarbob 2017-06-23 02:03:25

it means this object is greater than null. For the purposes of sorting, a null object reference "is less than" this object. That's just the way I decided to define how nulls will sort.

@Jude 2017-01-19 15:35:41

Anybody working with nullable types, Value is required to use CompareTo.

objListOrder.Sort((x, y) => x.YourNullableType.Value.CompareTo(y.YourNullableType.Value));

@itcropper 2016-08-22 18:45:36

None of the above answers were generic enough for me so I made this one:

var someUserInputStringValue = "propertyNameOfObject i.e. 'Quantity' or 'Date'";
var SortedData = DataToBeSorted
                   .OrderBy(m => m.GetType()
                                  .GetProperties()
                                  .First(n => 
                                      n.Name == someUserInputStringValue)
                   .GetValue(m, null))
                 .ToList();

Careful on massive data sets though. It's easy code but could get you in trouble if the collection is huge and the object type of the collection has a large number of fields. Run time is NxM where:

N = # of Elements in collection

M = # of Properties within Object

@molbalga 2016-07-19 10:18:06

Please let me complete the answer by @LukeH with some sample code, as I have tested it I believe it may be useful for some:

public class Order
{
    public string OrderId { get; set; }
    public DateTime OrderDate { get; set; }
    public int Quantity { get; set; }
    public int Total { get; set; }

    public Order(string orderId, DateTime orderDate, int quantity, int total)
    {
        OrderId = orderId;
        OrderDate = orderDate;
        Quantity = quantity;
        Total = total;
    }
}

public void SampleDataAndTest()
{
    List<Order> objListOrder = new List<Order>();

    objListOrder.Add(new Order("tu me paulo ", Convert.ToDateTime("01/06/2016"), 1, 44));
    objListOrder.Add(new Order("ante laudabas", Convert.ToDateTime("02/05/2016"), 2, 55));
    objListOrder.Add(new Order("ad ordinem ", Convert.ToDateTime("03/04/2016"), 5, 66));
    objListOrder.Add(new Order("collocationem ", Convert.ToDateTime("04/03/2016"), 9, 77));
    objListOrder.Add(new Order("que rerum ac ", Convert.ToDateTime("05/02/2016"), 10, 65));
    objListOrder.Add(new Order("locorum ; cuius", Convert.ToDateTime("06/01/2016"), 1, 343));


    Console.WriteLine("Sort the list by date ascending:");
    objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate));

    foreach (Order o in objListOrder)
        Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToString() + " Quantity = " + o.Quantity + " Total = " + o.Total);

    Console.WriteLine("Sort the list by date descending:");
    objListOrder.Sort((x, y) => y.OrderDate.CompareTo(x.OrderDate));
    foreach (Order o in objListOrder)
        Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToString() + " Quantity = " + o.Quantity + " Total = " + o.Total);

    Console.WriteLine("Sort the list by OrderId ascending:");
    objListOrder.Sort((x, y) => x.OrderId.CompareTo(y.OrderId));
    foreach (Order o in objListOrder)
        Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToString() + " Quantity = " + o.Quantity + " Total = " + o.Total);

    //etc ...
}

@Danny Mor 2015-04-02 08:01:48

You can do something more generic about the properties selection yet be specific about the type you're selecting from, in your case 'Order':

write your function as a generic one:

public List<Order> GetOrderList<T>(IEnumerable<Order> orders, Func<Order, T> propertySelector)
        {
            return (from order in orders
                    orderby propertySelector(order)
                    select order).ToList();
        } 

and then use it like this:

var ordersOrderedByDate = GetOrderList(orders, x => x.OrderDate);

You can be even more generic and define an open type for what you want to order:

public List<T> OrderBy<T,P>(IEnumerable<T> collection, Func<T,P> propertySelector)
        {
            return (from item in collection
                    orderby propertySelector(item)
                    select item).ToList();
        } 

and use it the same way:

var ordersOrderedByDate = OrderBy(orders, x => x.OrderDate);

Which is a stupid unnecessary complex way of doing a LINQ style 'OrderBy', But it may give you a clue of how it can be implemented in a generic way

@Lazarus 2010-07-22 13:16:56

The easiest way I can think of is to use Linq:

List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList();

@Bonus Kun 2013-02-13 17:03:12

how can I sort this in descending order.

@javajavajavajavajava 2013-02-20 14:18:58

@BonusKun List<Order> SortedList = objListOrder. OrderByDescending (o=>o.OrderDate).ToList();

@staafl 2013-10-19 19:25:21

note that this creates a whole new list with all the items in memory, which may be problematic in terms of performance.

@Andrew Grinder 2014-07-18 15:52:27

@staafl will listWithObjects = listWithObjects.OrderByDescending(o => o.Status).ToList(); suffice for such an endeavor?

@Lazarus 2015-04-22 18:36:06

@staafl We are ordering a list of object references, not duplicating the objects themselves as far as I'm aware. While this does double the memory used by the list of references it's not as bad as actually duplicating all of the objects themselves so in most scenarios outside of those where we are dealing with huge data sets and holding them in memory is already an issue, then it should suffice.

@Tyler Durden 2016-06-15 20:27:52

What happens if this property is nullable? Are the nulls ordered first?

@Lazarus 2016-06-17 12:28:17

That's dependent on the Comparer being used, so you could create a comparer to force your expected output. For the default comparer nulls come first as the lowest 'value'.

@marsop 2016-08-23 06:41:26

Is there a way to preserve the List cast? something like List<Order> SortedList = objListOrder.OrderByAsList(o=>o.OrderDate)

@TaW 2016-10-14 14:46:21

Question was: _ I need to sort it by the order date or order id_ How to do this dynamically??

@Lazarus 2016-11-27 09:45:16

@TaW Not sure what you mean here. Are you talking about a list that maintains sort order as new items are inserted and deleted so that it's always sorted? I'd suggest creating a new question to address this.

@TaW 2016-11-27 10:08:06

No. I meant he wanted to change sorting criteria dynamically. For this I think a Linq soluton would have to branch into two (or four to allow descending) linq expressions. The solution as written always does "order by OrderDate asc" . A dynamic solution would read: "order by " + criteriumName + " " + ascOrDescString.

@Ankush Madankar 2016-12-08 12:38:21

IQueryable would be great in such case to avoid local copies of object.

@Tyler C 2017-03-17 06:22:35

God this saved me, can confirm working Mar 2017 (in VS2017)

@Lazarus 2017-05-08 15:00:54

@sireeshaj Please search SO for the answer, I'm sure this has been covered in another question. If you can't find the answer then please create your own question, comments are not the place for further questions.

@SkinnyPete63 2018-03-23 09:10:30

I know this is an old thread, but this just saved me hours of work trying to implement some of the other proposed resolutions to this problem.

@uowzd01 2018-12-23 00:30:35

This method is slower than the answer below that uses List.Sort(delegate). List.Sort is NLogN, Linq OrderBy somehow is not NLogN

@Lazarus 2019-01-20 09:42:28

@uowzd01 That may be true but performance wasn't what the OP asked about. Best to keep questions and answers narrowly focused otherwise you end up with rambling comments like this.

@uowzd01 2019-01-21 09:30:33

@Lazarus In some scenario performance is very important, that's why I put a heads up here. Better to be open minded to suggestions otherwise you end up with inferior answer that you may never know.

@Jack Griffin 2015-01-06 13:47:38

Based on GenericTypeTea's Comparer :
we can obtain more flexibility by adding sorting flags :

public class MyOrderingClass : IComparer<Order> {  
    public int Compare(Order x, Order y) {  
        int compareDate = x.Date.CompareTo(y.Date);  
        if (compareDate == 0) {  
            int compareOrderId = x.OrderID.CompareTo(y.OrderID);  

            if (OrderIdDescending) {  
                compareOrderId = -compareOrderId;  
            }  
            return compareOrderId;  
        }  

        if (DateDescending) {  
            compareDate = -compareDate;  
        }  
        return compareDate;  
    }  

    public bool DateDescending { get; set; }  
    public bool OrderIdDescending { get; set; }  
}  

In this scenario, you must instantiate it as MyOrderingClass explicitly( rather then IComparer )
in order to set its sorting properties :

MyOrderingClass comparer = new MyOrderingClass();  
comparer.DateDescending = ...;  
comparer.OrderIdDescending = ...;  
orderList.Sort(comparer);  

@user3285954 2014-07-31 11:53:17

From performance point of view the best is to use a sorted list so that data is sorted as it is added to result. Other approaches need at least one extra iteration on data and most create a copy of data so not only performance but memory usage will be affected too. Might not be an issue with couple of hundreds of elements but will be with thousands, especially in services where many concurrent requests may do sorting at the same time. Have a look at System.Collections.Generic namespace and choose a class with sorting instead of List.

And avoid generic implementations using reflection when possible, this can cause performance issues too.

@John La Rooy 2017-12-05 20:41:41

How can this be more performant? Inserting data to a sorted list is O(n), so adding n items is O(n^2). What it many concurrent items are trying to be added? There are situations when you have extra CPU cycles to burn while items are being added, but this is not a good general solution.

@Peter 2014-02-14 14:25:06

Here is a generic LINQ extension method that does not create an extra copy of the list:

public static void Sort<T,U>(this List<T> list, Func<T, U> expression)
    where U : IComparable<U>
{
    list.Sort((x, y) => expression.Invoke(x).CompareTo(expression.Invoke(y)));
}

To use it:

myList.Sort(x=> x.myProperty);

I recently built this additional one which accepts an ICompare<U>, so that you can customize the comparison. This came in handy when I needed to do a Natural string sort:

public static void Sort<T, U>(this List<T> list, Func<T, U> expression, IComparer<U> comparer)
    where U : IComparable<U>
{    
    list.Sort((x, y) => comparer.Compare(expression.Invoke(x), expression.Invoke(y)));
}

@Rob L 2014-03-05 20:58:53

I've implemented this, works fine. I added an "isAscending = true" parameter. To sort in descending order, simply swap the x and y around within the two Invoke() methods. Thanks.

@Servy 2014-04-08 19:06:02

If you're just going to compile the expression you may as well just accept a delegate to begin with. Additionally, this approach has major problems if the selector causes side effects, is expensive to compute, or is not deterministic. A proper sorting based on a selected expression needs to invoke the selector no more than once per item in the list.

@Peter 2014-04-08 21:06:36

@Servy - those are all valid points, but I'll be honest, I'm not sure how to implement some of yoursuggestions (especially stopping a selector from causing side effects...?). I've changed them to delegates. If you know how to make some of those changes, I would be happy to have you edit my code.

@Servy 2014-04-08 21:08:20

@Peter You can't prevent the delegates from causing side effects. What you can do is ensure they're never called more than once per object, this means computing the values for each object, storing the object/projected-value pairs, and then sorting that. OrderBy does all of that internally.

@Jeppe Stig Nielsen 2017-01-30 11:59:04

Another nice way to write a void extension method in this spirit: static class Extensions { public static void SortBy<TSource, TKey>(this List<TSource> self, Func<TSource, TKey> keySelector) { self.SortBy(keySelector, Comparer<TKey>.Default); } public static void SortBy<TSource, TKey>(this List<TSource> self, Func<TSource, TKey> keySelector, IComparer<TKey> comparer) { self.Sort((x, y) => comparer.Compare(keySelector(x), keySelector(y))); } } Can be supplemented by a SortByDescending method. @Servy's comments apply to my code as well!

@Jimmy Hoffa 2010-07-22 13:55:21

Doing it without Linq as you said:

public class Order : IComparable
{
    public DateTime OrderDate { get; set; }
    public int OrderId { get; set; }

    public int CompareTo(object obj)
    {
        Order orderToCompare = obj as Order;
        if (orderToCompare.OrderDate < OrderDate || orderToCompare.OrderId < OrderId)
        {
            return 1;
        }
        if (orderToCompare.OrderDate > OrderDate || orderToCompare.OrderId > OrderId)
        {
            return -1;
        }

        // The orders are equivalent.
        return 0;
    }
}

Then just call .sort() on your list of Orders

@radarbob 2014-10-16 14:30:37

One must first test for null on the as cast. Which is the whole point of as, as (ha, ha) (Order)obj throws an exception when it fails. if(orderToCompare == null) return 1;.

@AeonOfTime 2015-11-06 22:29:56

+1 for using the interface, which makes the code easier to maintain and clearly exposes the object's capabilities.

@radarbob 2017-10-03 06:03:52

If Bill and Ted ever show up I'll ask them to take me back to Oct 16, 2014 so I can correct my mistake above - as returns null if the cast fails. But at least the null-test is right.

@Jimmy Hoffa 2017-11-07 16:01:29

@radarbob yeah.. oops. :) But! This function is intended to be used automatically by a sort over a list that is List<Order> so the type should be guaranteed to match on the as so 2014 you probably didn't write a bug, so much as avoiding an unnecessary guard statement :)

@radarbob 2017-11-07 21:31:17

should be guaranteed Interesting point. If it is well encapsulated such that it cannot be called except to pass a List<Order>; but you and I both have met the self-encapsulated programmer who's unspoken presumption is "i'm writing this code so it won't be used wrong"

@Miguel Becerra 2013-07-04 14:32:52

An improved of Roger's version.

The problem with GetDynamicSortProperty is that only get the property names but what happen if in the GridView we use NavigationProperties? it will send an exception, since it finds null.

Example:

"Employee.Company.Name; " will crash... since allows only "Name" as a parameter to get its value.

Here's an improved version that allows us to sort by Navigation Properties.

public object GetDynamicSortProperty(object item, string propName)
    {
        try
        {                 
            string[] prop = propName.Split('.'); 

            //Use reflection to get order type                   
            int i = 0;                    
            while (i < prop.Count())
            {
                item = item.GetType().GetProperty(prop[i]).GetValue(item, null);
                i++;
            }                     

            return item;
        }
        catch (Exception ex)
        {
            throw ex;
        }


    } 

@roger 2013-06-13 01:37:08

// Totally generic sorting for use with a gridview

public List<T> Sort_List<T>(string sortDirection, string sortExpression, List<T> data)
    {

        List<T> data_sorted = new List<T>();

        if (sortDirection == "Ascending")
        {
            data_sorted = (from n in data
                              orderby GetDynamicSortProperty(n, sortExpression) ascending
                              select n).ToList();
        }
        else if (sortDirection == "Descending")
        {
            data_sorted = (from n in data
                              orderby GetDynamicSortProperty(n, sortExpression) descending
                              select n).ToList();

        }

        return data_sorted;

    }

    public object GetDynamicSortProperty(object item, string propName)
    {
        //Use reflection to get order type
        return item.GetType().GetProperty(propName).GetValue(item, null);
    }

@gunr2171 2013-06-13 01:41:32

Or, you know, data.OrderBy(). Bit easier that re-inventing the wheel.

@roger 2013-10-01 06:01:10

The idea is this will work with any type of object. Where as OrderBy() only works with strongly typed objects.

@kostas ch. 2015-01-29 06:45:13

Thx a lot.On my opinion ,the most simple and usable solution sorting grid data!

@Waqas Ahmed 2011-11-23 21:42:33

//Get data from database, then sort list by staff name:

List<StaffMember> staffList = staffHandler.GetStaffMembers();

var sortedList = from staffmember in staffList
                 orderby staffmember.Name ascending
                 select staffmember;

@djdd87 2010-07-22 13:35:08

To do this without LINQ on .Net2.0:

List<Order> objListOrder = GetOrderList();
objListOrder.Sort(
    delegate(Order p1, Order p2)
    {
        return p1.OrderDate.CompareTo(p2.OrderDate);
    }
);

If you're on .Net3.0, then LukeH's answer is what you're after.

To sort on multiple properties, you can still do it within a delegate. For example:

orderList.Sort(
    delegate(Order p1, Order p2)
    {
        int compareDate = p1.Date.CompareTo(p2.Date);
        if (compareDate == 0)
        {
            return p2.OrderID.CompareTo(p1.OrderID);
        }
        return compareDate;
    }
);

This would give you ascending dates with descending orderIds.

However, I wouldn't recommend sticking delegates as it will mean lots of places without code re-use. You should implement an IComparer and just pass that through to your Sort method. See here.

public class MyOrderingClass : IComparer<Order>
{
    public int Compare(Order x, Order y)
    {
        int compareDate = x.Date.CompareTo(y.Date);
        if (compareDate == 0)
        {
            return x.OrderID.CompareTo(y.OrderID);
        }
        return compareDate;
    }
}

And then to use this IComparer class, just instantiate it and pass it to your Sort method:

IComparer<Order> comparer = new MyOrderingClass();
orderList.Sort(comparer);

@wonton 2013-10-14 01:04:15

Would it be a good idea to use Singleton for the comparator?

@Jeb 2014-09-30 16:01:38

Excellent answer, and should be the correct one as it protects re-initializing the original list (which the LINQ version will always do) providing better encapsulation.

@radarbob 2014-10-16 14:55:31

@wonton, no. The idea is to be able to have different IComparer implementations, giving us polymorphic behavior.

@Jack Griffin 2015-01-06 13:51:42

Worked for me. I posted a version of this with sorting options.

@Pranay Rana 2010-07-22 13:16:31

Make use of LiNQ OrderBy

List<Order> objListOrder=new List<Order> ();
    objListOrder=GetOrderList().OrderBy(o=>o.orderid).ToList();

@Daniel A. White 2010-07-22 13:16:27

Using LINQ

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderDate)
                   .ToList();

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderId)
                   .ToList();

Related Questions

Sponsored Content

42 Answered Questions

[SOLVED] Sort array of objects by string property value

44 Answered Questions

[SOLVED] How to make a flat list out of list of lists

20 Answered Questions

[SOLVED] LINQ's Distinct() on a particular property

45 Answered Questions

[SOLVED] Deep cloning objects

  • 2008-09-17 00:06:27
  • NakedBrunch
  • 760962 View
  • 2096 Score
  • 45 Answer
  • Tags:   c# .net clone

26 Answered Questions

[SOLVED] Why not inherit from List<T>?

28 Answered Questions

[SOLVED] How do I check if a list is empty?

  • 2008-09-10 06:20:11
  • Ray Vega
  • 2414402 View
  • 3235 Score
  • 28 Answer
  • Tags:   python list

16 Answered Questions

34 Answered Questions

[SOLVED] How do I sort a dictionary by value?

18 Answered Questions

[SOLVED] How do you sort a dictionary by value?

25 Answered Questions

[SOLVED] Sort ArrayList of custom Objects by property

Sponsored Content