Как отсортировать список по свойству в объекте
у меня есть класс с именем Order который имеет такие свойства, как OrderId,OrderDate,Quantity и Total. У меня есть список этого Order класс:
List<Order> objListOrder = new List<Order>();
GetOrderList(objListOrder); // fill list of orders
теперь я хочу отсортировать список на основе одного свойства
19 ответов:
самый простой способ, который я могу придумать, это использовать Linq:
List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList();
Если вам нужно отсортировать список на месте, то вы можете использовать
Sortметод, передающий aComparison<T>делегат:objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate));если вы предпочитаете создавать новую, отсортированную последовательность, а не сортировать на месте, то вы можете использовать LINQ's
OrderByметод, как упоминалось в других ответах.
чтобы сделать это без LINQ on. Net2. 0:
List<Order> objListOrder = GetOrderList(); objListOrder.Sort( delegate(Order p1, Order p2) { return p1.OrderDate.CompareTo(p2.OrderDate); } );если вы на. Net3. 0, то LukeH ответ это то, что вам нужно.
Сортировать по нескольким свойствам, вы все еще можете сделать это в течение делегата. Например:
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; } );это даст вам по возрастанию период с спуск orderIds.
однако я бы не рекомендовал вставлять делегатов, поскольку это будет означать много мест без повторного использования кода. Вы должны реализовать
IComparerи просто передайте это своемуSortметод. Смотрите здесь.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; } }и затем, чтобы использовать этот класс IComparer, просто создайте его экземпляр и передайте его своему методу сортировки:
IComparer<Order> comparer = new MyOrderingClass(); orderList.Sort(comparer);
самый простой способ заказать список-использовать
OrderByList<Order> objListOrder = source.OrderBy(order => order.OrderDate).ToList();если вы хотите заказать по нескольким столбцам, как следующий SQL-запрос.
ORDER BY OrderDate, OrderIdдля достижения этой цели вы можете использовать
ThenByкак следующим.List<Order> objListOrder = source.OrderBy(order => order.OrderDate).ThenBy(order => order.OrderId).ToList();
делать это без Linq, как вы сказали:
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; } }тогда просто позвоните .сортировка () в вашем списке заказов
Классическое Объектно-Ориентированное Решение
сначала я должен преклонить колени перед удивительностью LINQ.... Теперь, когда мы убрали это с дороги
вариация на ответ Джиммихоффа. С дженериками то
CompareToпараметр становится типобезопасным.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();эта сортируемость по умолчанию, конечно, может использоваться повторно. То есть каждый клиент не должен избыточно переписывать логику сортировки. Замена "1" и "-1" (или логические операторы, ваш выбор) изменяет порядок сортировки.
/ / полностью общая сортировка для использования с 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); }
вот общий метод расширения LINQ, который не создает дополнительную копию списка:
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))); }использовать:
myList.Sort(x=> x.myProperty);Я недавно построил этот дополнительный, который принимает
ICompare<U>, Так что вы можете настроить сравнение. Это пригодилось, когда мне нужно было сделать естественную сортировку строк: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))); }
С помощью LINQ
objListOrder = GetOrderList() .OrderBy(o => o.OrderDate) .ToList(); objListOrder = GetOrderList() .OrderBy(o => o.OrderId) .ToList();
//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;
улучшенная версия Роджера.
проблема с GetDynamicSortProperty заключается в том, что только получить имена свойств, но что произойдет, если в GridView мы используем NavigationProperties? он отправит исключение, так как он находит null.
пример:
"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; } }
вы можете сделать что-то более общее о выборе свойств, но быть конкретным о типе, который вы выбираете, в вашем случае "порядок":
напишите свою функцию как общую:
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', Но это может дать вам представление о том, как это может быть реализовано в общем виде
Пожалуйста, позвольте мне завершить ответ @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 ... }
ни один из приведенных выше ответов не был достаточно общим для меня, поэтому я сделал это:
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 = # свойств внутри объекта
используйте LiNQ
OrderByList<Order> objListOrder=new List<Order> (); objListOrder=GetOrderList().OrderBy(o=>o.orderid).ToList();
на основе GenericTypeTea'ы компаратор :
мы можем получить большую гибкость, добавив флаги сортировки: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);
с точки зрения производительности лучше всего использовать сортированный список, чтобы данные сортировались по мере их добавления в результат. Другие подходы требуют по крайней мере одну дополнительную итерацию данных и большинство из них создают копию данных, поэтому не только производительность, но и использование памяти также будут затронуты. Возможно, это не проблема с несколькими сотнями элементов, но будет с тысячами, особенно в службах, где многие параллельные запросы могут выполнять сортировку одновременно. Взгляните на систему.Коллекции.Родовой пространство имен и выберите класс с сортировкой вместо списка.
и избегайте общих реализаций с использованием отражения, когда это возможно, это также может вызвать проблемы с производительностью.
любой, кто работает с типами nullable,
Valueнеобходимо использоватьCompareTo.
objListOrder.Sort((x, y) => x.YourNullableType.Value.CompareTo(y.YourNullableType.Value));
Comments