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

1621
我有一个名为Order的类,它具有诸如OrderIdOrderDateQuantityTotal等属性。我有一个这个Order类的列表:
List<Order> objListOrder = new List<Order>();
GetOrderList(objListOrder); // fill list of orders

我想根据Order对象的一个属性对列表进行排序;例如,根据OrderDateOrderID进行排序。
在C#中,我该如何实现这个功能?
24个回答

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

4
//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;

3
你可以在属性选择方面做一些更通用的事情,但要针对你选择的类型进行具体说明,例如“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”,但它可能会给你一个通用实现的线索。


3

罗杰版本的改进。

GetDynamicSortProperty存在问题,它只获取属性名称,但是如果在GridView中使用NavigationProperties会怎样呢?它将抛出异常,因为它找到了null。

例如:

"Employee.Company.Name; " 将崩溃...... 因为只允许使用 "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
var obj = db.Items.Where...

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

2

利用 LiNQ OrderBy 函数

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

2
假设您有以下代码,在此代码中,我们有一个乘客类,其中包含我们想要基于其排序的一些属性。
假设您有以下代码,在此代码中,我们有一个乘客类,其中包含我们想要基于其排序的一些属性。
public class Passenger
{
    public string Name { get; }
    public string LastName { get; }
    public string PassportNo { get; }
    public string Nationality { get; }

    public Passenger(string name, string lastName, string passportNo, string nationality)
    {
        this.Name = name;
        this.LastName = lastName;
        this.PassportNo = passportNo;
        this.Nationality = nationality;
    }

    public static int CompareByName(Passenger passenger1, Passenger passenger2)
    {
        return String.Compare(passenger1.Name, passenger2.Name);
    }

    public static int CompareByLastName(Passenger passenger1, Passenger passenger2)
    {
        return String.Compare(passenger1.LastName, passenger2.LastName);
    }

    public static int CompareNationality(Passenger passenger1, Passenger passenger2)
    {
        return String.Compare(passenger1.Nationality, passenger2.Nationality);
    }
}

public class TestPassengerSort
{
    Passenger p1 = new Passenger("Johon", "Floid", "A123456789", "USA");
    Passenger p2 = new Passenger("Jo", "Sina", "A987463215", "UAE");
    Passenger p3 = new Passenger("Ped", "Zoola", "A987855215", "Italy");

    public void SortThem()
    {
        Passenger[] passengers = new Passenger[] { p1, p2, p3 };
        List<Passenger> passengerList = new List<Passenger> { p1, p2, p3 };

        Array.Sort(passengers, Passenger.CompareByName);
        Array.Sort(passengers, Passenger.CompareByLastName);
        Array.Sort(passengers, Passenger.CompareNationality);

        passengerList.Sort(Passenger.CompareByName);
        passengerList.Sort(Passenger.CompareByLastName);
        passengerList.Sort(Passenger.CompareNationality);

    }
}

因此,您可以通过使用组合委托来实现排序结构。

2
扩展方法用于原地排序列表。它具有与LINQ OrderBy相似的签名和空值处理方式。
public static void SortBy<T, TKey>(this List<T> list, Func<T, TKey> selector, IComparer<TKey>? comparer = null)
{
    comparer ??= Comparer<TKey>.Default;
    list.Sort((a, b) => comparer.Compare(selector(a), selector(b)));
}

public static void SortByDescending<T, TKey>(this List<T> list, Func<T, TKey> selector, IComparer<TKey>? comparer = null)
{
    comparer ??= Comparer<TKey>.Default;
    list.Sort((a, b) => comparer.Compare(selector(b), selector(a)));
}

使用方法:

items.SortBy(x => x.FullName);
items.SortBy(x => x.FullName, StringComparer.Ordinal);

ValueTuples提供了一种方便的方式,可以使用默认比较器按照相同的顺序进行sortBy + thenBy操作。
items.SortBy(x => (x.FirstName, x.LastName));

1
根据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);  

1

以上答案都不够通用,所以我写了这个:

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 = 对象内属性数量

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接