c# - desc - unity list sort




如何按對像中的屬性對List<T>進行排序 (13)

我有一個名為Order的類,它具有OrderIdOrderDateQuantityTotal等屬性。 我有這個Order類的列表:

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

現在我想根據Order對象的一個屬性對列表進行排序,例如我需要按訂單日期或訂單ID對其進行排序。

我如何在C#中執行此操作?


//完全通用的排序與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的迷人魅力進行歸納....現在我們已經取得了進展

JimmyHoffa答案的變化。 使用泛型時, 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”(或邏輯運算符,您的選擇)顛倒排序順序。


任何使用可空類型的人都必須使用Value來使用CompareTo

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


使用LINQ

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

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

在.Net2.0上不使用LINQ來做到這一點:

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

如果你使用.Net3.0,那麼LukeH的answer就是你要做的。

要對多個屬性進行排序,您仍然可以在委託中進行排序。 例如:

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方法。 看到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;
    }
}

然後使用這個IComparer類,實例化它並將它傳遞給你的Sort方法:

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

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

如果您需要在原地排序列表,則可以使用Sort方法,傳遞一個Comparison<T>委託:

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

如果您更喜歡創建一個新的排序序列,而不是就地排序,那麼您可以使用LINQ的OrderBy方法,如其他答案中所述。


從性能角度來看,最好的方法是使用排序列表,以便數據在添加結果時進行排序。 其他方法至少需要對數據進行一次額外迭代,大多數方法會創建數據副本,這樣不僅性能,而且內存使用率也會受到影響。 可能不是幾百個元素的問題,但會有數千個問題,特別是在許多並發請求可能同時進行排序的服務中。 查看System.Collections.Generic命名空間並選擇一個具有排序而不是List的類。

盡可能避免使用反射的泛型實現,這也會導致性能問題。


我能想到的最簡單的方法是使用Linq:

List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).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()


請讓我用@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 ...
}

這是一個通用的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)));
}

var obj = db.Items.Where...

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




sorting