如何通过对象中的属性对List <T>进行排序

Shy*_*yju 1146 c# sorting generics list

我有一个名为类Order具有如属性OrderId,OrderDate,Quantity,和Total.我有这个Order类的列表:

List<Order> objListOrder = new List<Order>();
GetOrderList(objListOrder); // fill list of orders
Run Code Online (Sandbox Code Playgroud)

现在我想根据Order对象的一个属性对列表进行排序,例如我需要按订单日期或订单ID对其进行排序.

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

Laz*_*rus 1668

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

List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList();
Run Code Online (Sandbox Code Playgroud)

  • @BonusKun List <Order> SortedList = objListOrder.**OrderByDescending**(o => o.OrderDate).ToList(); (205认同)
  • 请注意,这将创建一个包含内存中所有项目的全新列表,**可能*在性能方面存在问题. (70认同)
  • @staafl我们正在订购一个对象引用列表,而不是像我所知的那样复制对象本身.虽然这会使引用列表使用的内存加倍,但它并没有实际复制所有对象本身那么糟糕,所以在我们处理大量数据集并将它们保存在内存中的大多数场景中已经是一个问题,然后它应该足够了. (24认同)
  • 我怎样才能按降序排序. (17认同)
  • @staafl将`listWithObjects = listWithObjects.OrderByDescending(o => o.Status).ToList();`这样的努力是否足够? (13认同)
  • @sireeshaj请搜索SO以获得答案,我确信这已经包含在另一个问题中.如果您找不到答案,请创建您自己的问题,评论不是进一步问题的地方. (2认同)
  • 此方法比下面使用List.Sort(delegate)的答案要慢。List.Sort是NLogN,Linq Order由于某种原因不是NLogN (2认同)

Luk*_*keH 708

如果您需要就地对列表进行排序,那么您可以使用该Sort方法,传递Comparison<T>委托:

objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate));
Run Code Online (Sandbox Code Playgroud)

如果您希望创建一个新的排序序列而不是就地排序,那么您可以使用LINQ的OrderBy方法,如其他答案中所述.

  • 当然,如果你需要降序排序,请在箭头`=>`的右侧交换`x`和`y`. (38认同)
  • 是的,这是"正确的"答案,应该比创建新的IEnumerable然后将其转换为新列表更有效. (22认同)
  • 真正的答案,实际上就地排序列表 (15认同)
  • @JonSchneider对于`Nullable <>`(以`DateTime?`为例)你可以使用`.Sort((x,y)=> Nullable.Compare(x.OrderDate,y.OrderDate))`这将处理null在所有非空值之前.它与`.Sort((x,y)=> Comparer <DateTime?>.Default.Compare(x.OrderDate,y.OrderDate)`完全相同. (10认同)
  • @PimBrouwers这是更好的选择期.即使您使用的内存量不是问题,此解决方案也避免了不必要的内存分配,这种分配非常昂贵.此选项与代码一样简单,速度快一个数量级. (2认同)
  • 疯狂挑剔,但使用a,b代替x,y进行排序更为常见。 (2认同)

djd*_*d87 211

要在.Net2.0上没有LINQ的情况下执行此操作:

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

如果您使用的是.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;
    }
);
Run Code Online (Sandbox Code Playgroud)

这将为您提供降序 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用这个IComparer类,只需实例化它并将其传递给Sort方法:

IComparer<Order> comparer = new MyOrderingClass();
orderList.Sort(comparer);
Run Code Online (Sandbox Code Playgroud)


PSK*_*PSK 102

订购列表的最简单方法是使用 OrderBy

 List<Order> objListOrder = 
    source.OrderBy(order => order.OrderDate).ToList();
Run Code Online (Sandbox Code Playgroud)

如果您想按照SQL Query之类的多个列进行排序.

ORDER BY OrderDate, OrderId
Run Code Online (Sandbox Code Playgroud)

为此,您可以使用ThenBy以下内容.

  List<Order> objListOrder = 
    source.OrderBy(order => order.OrderDate).ThenBy(order => order.OrderId).ToList();
Run Code Online (Sandbox Code Playgroud)


Jim*_*ffa 32

没有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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的订单列表上调用.sort()

  • 首先必须在`as`演员表上测试`null`.这是"as"的全部要点,因为(ha,ha)`(Order)obj`在失败时抛出异常.`if(orderToCompare == null)返回1;`. (3认同)

rad*_*bob 24

一种经典的面向对象解决方案

首先,我必须接受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(); 
Run Code Online (Sandbox Code Playgroud)

当然,此默认可排序性是可重用的.也就是说,每个客户端都不必冗余地重写排序逻辑.交换"1"和"-1"(或逻辑运算符,您的选择)会反转排序顺序.

  • 它意味着`this`对象大于null.出于排序的目的,空对象引用"小于"`this`对象.这就是我决定定义空值如何排序的方式. (2认同)

rog*_*ger 18

//用于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);
    }
Run Code Online (Sandbox Code Playgroud)

  • 或者,你知道,`data.OrderBy()`.更容易重新发明轮子. (4认同)
  • 这个想法是适用于任何类型的对象.OrderBy()仅适用于强类型对象. (4认同)

Jud*_*ude 8

任何使用可空类型的人Value都需要使用CompareTo.

objListOrder.Sort((x, y) => x.YourNullableType.Value.CompareTo(y.YourNullableType.Value));
Run Code Online (Sandbox Code Playgroud)


Dan*_*ite 6

使用 LINQ

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

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderId)
                   .ToList();
Run Code Online (Sandbox Code Playgroud)


Pet*_*ter 6

这是一个通用的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)));
}
Run Code Online (Sandbox Code Playgroud)

要使用它:

myList.Sort(x=> x.myProperty);
Run Code Online (Sandbox Code Playgroud)

我最近构建了另外一个接受一个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)));
}
Run Code Online (Sandbox Code Playgroud)

  • @Peter你*不能*阻止代表造成副作用.你可以做的是确保每个对象永远不会被调用一次,这意味着计算每个对象的值,存储对象/投影值对,然后排序*that*.`OrderBy`在内部完成所有这些工作. (2认同)

小智 5

请让我用一些示例代码来完成@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 ...
}
Run Code Online (Sandbox Code Playgroud)