Как отсортировать список <T>по свойству объекта - PullRequest
1081 голосов
/ 22 июля 2010

У меня есть класс с именем Order, который имеет такие свойства, как OrderId, OrderDate, Quantity и Total. У меня есть список этого Order класса:

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

Теперь я хочу отсортировать список на основе одного свойства объекта Order, например, мне нужно отсортировать его по дате заказа или идентификатору заказа.

Как я могу сделать это в C #?

Ответы [ 19 ]

3 голосов
/ 31 мая 2017
var obj = db.Items.Where...

var orderBYItemId = obj.OrderByDescending(c => Convert.ToInt32(c.ID));
3 голосов
/ 04 июля 2013

Улучшенная версия Роджера.

Проблема с GetDynamicSortProperty состоит в том, что только получают имена свойств, но что произойдет, если в GridView мы используем NavigationProperties?он отправит исключение, так как находит нулевое значение.

Пример:

"Employee.Company.Name;" завершится сбоем ..., поскольку позволяет только "Имя" в качестве параметра получить егозначение.

Вот улучшенная версия, которая позволяет сортировать по свойствам навигации.

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;
        }


    } 
3 голосов
/ 19 июля 2016

Пожалуйста, дайте мне дополнить ответ @LukeH примером кода, так как я проверял его, я думаю, что он может быть полезен для некоторых:

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 ...
}
3 голосов
/ 02 апреля 2015

Вы можете сделать что-то более общее с выбором свойств, но быть конкретным с типом, из которого вы выбираете, в вашем случае 'Order':

написать свою функцию как универсальную:

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

, а затем используйте его так:

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

Вы можете быть еще более универсальным и определить открытый тип для того, что вы хотите заказать:

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

и использоватьэто так же:

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

Это глупый ненужный сложный способ выполнения стиля LINQ 'OrderBy', но он может дать вам подсказку о том, как его можно реализовать в общем виде

1 голос
/ 19 января 2017

Любой, кто работает с обнуляемыми типами, Value должен использовать CompareTo.

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

1 голос
/ 22 августа 2016

Ни один из приведенных выше ответов не был достаточно общим для меня, поэтому я сделал этот:

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();

Осторожнее с массивами данных. Это простой код, но он может доставить вам неприятности, если коллекция огромна, а тип объекта коллекции имеет большое количество полей. Время выполнения NxM, где:

N = Количество элементов в коллекции

M = Количество свойств внутри объекта

1 голос
/ 06 января 2015

На основе GenericTypeTea 's Comparer:
мы можем добиться большей гибкости, добавив флаги сортировки:

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; }  
}  

В этом сценарии его необходимо создать как MyOrderingClass явно (а не IComparer )
для установки его свойств сортировки:

MyOrderingClass comparer = new MyOrderingClass();  
comparer.DateDescending = ...;  
comparer.OrderIdDescending = ...;  
orderList.Sort(comparer);  
1 голос
/ 22 июля 2010

Используйте LiNQ OrderBy

List<Order> objListOrder=new List<Order> ();
    objListOrder=GetOrderList().OrderBy(o=>o.orderid).ToList();
0 голосов
/ 31 июля 2014

С точки зрения производительности лучше всего использовать отсортированный список, чтобы данные сортировались по мере их добавления в результат. Другие подходы требуют, по крайней мере, одну дополнительную итерацию для данных, и большинство создает копию данных, так что это влияет не только на производительность, но и на использование памяти. Может не быть проблем с парой сотен элементов, но будет с тысячами, особенно в сервисах, где многие одновременные запросы могут выполнять сортировку одновременно. Взгляните на пространство имен System.Collections.Generic и выберите класс с сортировкой вместо List.

И избегайте универсальных реализаций, использующих отражение, когда это возможно, это может также вызвать проблемы с производительностью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...