如何按对象中的属性对List <T>进行sorting

我有一个名为Order的类,它具有OrderIdOrderDateQuantityTotal等属性。 我有这个Order类的列表:

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

现在我想基于Order对象的一个​​属性对列表进行sorting,例如我需要按订单date或订单ID进行sorting。

我怎么能在C#中做到这一点?

我能想到的最简单的方法是使用Linq:

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

如果你需要就地sorting列表,那么你可以使用Sort方法,传递一个Comparison<T>委托:

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

如果您更喜欢创build一个新的sorting序列,而不是就地sorting,那么您可以使用LINQ的OrderBy方法,如其他答案中所述。

在.Net2.0上不使用LINQ来做到这一点:

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

如果你使用的是.Net3.0,那么LukeH的回答就是你要的。

要对多个属性进行sorting,您仍然可以在委托中进行sorting。 例如:

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

这会给你升序date降序 orderIds。

不过,我不build议坚持代表,因为这将意味着很多地方没有代码重用。 你应该实现一个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类,只是实例化它,并将其传递给你的sorting方法:

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

如果你想要的东西

 ORDER BY OrderDate, OrderId 

然后尝试如下。

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

然后在订单列表中调用.sort()

面向对象的经典解决scheme

首先,我必须感受LINQ的迷人之处….现在,我们已经得到了这一点

JimmyHoffa答案的变化。 在generics中, CompareTo参数变成types安全的。

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

这种默认的sortingfunction当然是可以重复使用的。 这是每个客户端不必冗余地重新编写sorting逻辑。 交换“1”和“-1”(或逻辑运算符,您的select)颠倒sorting顺序。

//完全通用的sorting与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扩展方法,不会创build列表的额外副本:

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

我最近build立了这个额外的接受一个ICompare<U> ,以便您可以自定义比较。 当我需要做一个自然的stringsorting时,这个方法很方便:

 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; 

你可以做一些更通用的属性select,但具体关于你select的types,在你的情况'订单':

把你的函数写成一个通用的函数:

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

你可以更通用的定义一个你想要订购的开放types:

 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用一些示例代码来完成答案,因为我已经testing了它,我相信它对于某些人可能是有用的:

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

罗杰版本的改进。

GetDynamicSortProperty的问题是只获取属性名称,但如果在GridView中使用NavigationProperties,会发生什么? 它会发送一个exception,因为它发现null。

例:

“Employee.Company.Name;”将崩溃…因为只允许“Name”作为参数来获取其值。

这是一个改进的版本,允许我们按照导航属性进行sorting。

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

上面的答案都不是通用的,所以我做了这个:

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

小心大量的数据集。 这是简单的代码,但如果集合是巨大的,集合的对象types有大量的字段可能会麻烦你。 运行时间是NxM其中:

N =收集中的元素数量

M =对象内的属性数量

利用LiNQ OrderBy

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

从性能angular度来看,最好的方法是使用sorting列表,以便数据在添加结果时进行sorting。 其他方法至less需要对数据进行一次额外的迭代,而且大多数情况下都会创build数据的副本,这样不仅性能而且内存使用也会受到影响。 可能不是几百个元素的问题,但会有数千个问题,特别是在许多并发请求可能同时进行sorting的服务中。 看看System.Collections.Generic命名空间,并select一个类,而不是列表。

尽可能避免使用reflection的generics实现,这也会导致性能问题。

基于GenericTypeTea的比较器:
我们可以通过添加sorting标志来获得更多的灵活

 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
为了设置它的sorting属性:

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

任何使用可空types的人都必须使用Value来使用CompareTo

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

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