it-swarm.com.de

So sortieren Sie eine Liste <T> nach einer Eigenschaft im Objekt

Ich habe eine Klasse namens Order mit Eigenschaften wie OrderId, OrderDate, Quantity und Total. Ich habe eine Liste dieser Order Klasse:

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

Jetzt möchte ich die Liste basierend auf einer Eigenschaft des Objekts Order sortieren. Beispielsweise muss ich sie nach dem Bestelldatum oder der Bestell-ID sortieren.

Wie kann ich das in C # machen?

1105
Shyju

Am einfachsten fällt mir die Verwendung von Linq ein:

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

Wenn Sie die Liste direkt sortieren müssen, können Sie die Sort -Methode verwenden und einen Comparison<T> -Delegaten übergeben:

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

Wenn Sie es vorziehen, eine neue, sortierte Sequenz zu erstellen, anstatt direkt zu sortieren, können Sie die in den anderen Antworten erwähnte Methode OrderBy von LINQ verwenden.

678
LukeH

So tun Sie dies ohne LINQ unter .Net2.0:

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

Wenn Sie auf .Net3.0 sind, ist LukeHs Antwort genau das, wonach Sie suchen.

Um nach mehreren Eigenschaften zu sortieren, können Sie dies immer noch innerhalb eines Delegaten tun. Zum Beispiel:

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

Dies würde Ihnen aufsteigende Daten mit absteigenden orderIds geben.

Ich würde jedoch nicht empfehlen, Delegierte zu halten, da dies viele Stellen ohne Wiederverwendung von Code bedeuten wird. Sie sollten eine IComparer implementieren und diese einfach an Ihre Sort -Methode übergeben. Siehe hier .

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

Um diese IComparer-Klasse zu verwenden, müssen Sie sie nur instanziieren und an Ihre Sort-Methode übergeben:

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

Die einfachste Möglichkeit, eine Liste zu bestellen, ist die Verwendung von OrderBy

 List<Order> objListOrder = 
    source.OrderBy(order => order.OrderDate).ToList();

Wenn Sie nach mehreren Spalten wie in der folgenden SQL-Abfrage sortieren möchten.

ORDER BY OrderDate, OrderId

Um dies zu erreichen, können Sie ThenBy wie folgt verwenden.

  List<Order> objListOrder = 
    source.OrderBy(order => order.OrderDate).ThenBy(order => order.OrderId).ToList();
98
PSK

Mach es ohne Linq wie du gesagt hast:

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

Dann rufen Sie einfach .sort () auf Ihrer Bestellliste an

32
Jimmy Hoffa

Eine klassische objektorientierte Lösung

Zuerst muss ich mich an die Faszination von LINQ gewöhnen ... Jetzt, wo wir das aus dem Weg haben

Eine Variation der JimmyHoffa-Antwort. Mit Generics wird der Parameter CompareTo typsicher.

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

Diese Standardsortierbarkeit ist natürlich wieder verwendbar. Das heißt, jeder Client muss die Sortierlogik nicht redundant umschreiben. Durch Vertauschen von "1" und "-1" (oder der von Ihnen gewählten logischen Operatoren) wird die Sortierreihenfolge umgekehrt.

23
radarbob

// Völlig generische Sortierung zur Verwendung mit einer Rasteransicht

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

Hier ist eine generische LINQ-Erweiterungsmethode, mit der keine zusätzliche Kopie der Liste erstellt wird:

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

Um es zu benutzen:

myList.Sort(x=> x.myProperty);

Ich habe kürzlich dieses zusätzliche gebaut, das einen ICompare<U> akzeptiert, damit Sie den Vergleich anpassen können. Dies hat sich als nützlich erwiesen, als ich eine natürliche Zeichenfolgensortierung durchführen musste:

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

LINQ verwenden

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

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderId)
                   .ToList();
4
Daniel A. White
//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
Waqas Ahmed

Eine Verbesserung von Rogers Version.

Das Problem mit GetDynamicSortProperty ist, dass nur die Eigenschaftsnamen abgerufen werden. Was passiert jedoch, wenn in der GridView NavigationProperties verwendet wird? es wird eine Ausnahme gesendet, da es null findet.

Beispiel:

"Employee.Company.Name;" stürzt ab ... da nur "Name" als Parameter seinen Wert erhält.

Hier ist eine verbesserte Version, mit der wir nach Navigationseigenschaften sortieren können.

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
user1013375

Sie können etwas allgemeineres in Bezug auf die Auswahl der Eigenschaften tun, aber den Typ, aus dem Sie auswählen, genau festlegen, in Ihrem Fall "Reihenfolge":

schreiben Sie Ihre Funktion als generische:

public List<Order> GetOrderList<T>(IEnumerable<Order> orders, Func<Order, T> propertySelector)
        {
            return (from order in orders
                    orderby propertySelector(order)
                    select order).ToList();
        } 

und benutze es dann so:

var ordersOrderedByDate = GetOrderList(orders, x => x.OrderDate);

Sie können noch allgemeiner sein und einen offenen Typ für das definieren, was Sie bestellen möchten:

public List<T> OrderBy<T,P>(IEnumerable<T> collection, Func<T,P> propertySelector)
        {
            return (from item in collection
                    orderby propertySelector(item)
                    select item).ToList();
        } 

und benutze es genauso:

var ordersOrderedByDate = OrderBy(orders, x => x.OrderDate);

Dies ist eine dumme, unnötig komplexe Methode, um einen LINQ-Stil "OrderBy" zu erstellen. Sie gibt Ihnen jedoch möglicherweise einen Hinweis darauf, wie er generisch implementiert werden kann

3
Danny Mor

Bitte lassen Sie mich die Antwort von @LukeH mit einem Beispielcode vervollständigen, da ich ihn getestet habe. Ich glaube, dass er für einige nützlich sein kann:

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 ...
}
3
molbalga
var obj = db.Items.Where...

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

Keine der obigen Antworten war generisch genug für mich, also habe ich diese gemacht:

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

Vorsicht bei großen Datenmengen. Es ist einfacher Code, kann jedoch zu Problemen führen, wenn die Auflistung sehr umfangreich ist und der Objekttyp der Auflistung eine große Anzahl von Feldern enthält. Die Laufzeit ist NxM, wobei:

N = Anzahl der Elemente in der Sammlung

M = Anzahl der Eigenschaften innerhalb des Objekts

1
itcropper

Jeder, der mit nullbaren Typen, Value, arbeitet, muss CompareTo verwenden.

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

1
Jude

Nutzen Sie LiNQ OrderBy

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

Basierend auf dem Vergleich von GenericTypeTea:
Wir können mehr Flexibilität erhalten, indem wir Sortierflags hinzufügen:

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

In diesem Szenario müssen Sie es als MyOrderingClass explizit instanziieren (statt IComparer)
um die Sortiereigenschaften einzustellen:

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

Aus Sicht der Leistung ist es am besten, eine sortierte Liste zu verwenden, damit die Daten sortiert werden, wenn sie zum Ergebnis hinzugefügt werden. Andere Ansätze erfordern mindestens eine zusätzliche Iteration der Daten und die meisten erstellen eine Kopie der Daten, sodass nicht nur die Leistung, sondern auch die Speichernutzung beeinträchtigt wird. Dies ist möglicherweise kein Problem bei einigen Hundert Elementen, wird jedoch bei Tausenden auftreten, insbesondere bei Diensten, bei denen möglicherweise viele gleichzeitige Anforderungen gleichzeitig sortiert werden. Sehen Sie sich den System.Collections.Generic-Namespace an und wählen Sie eine Klasse mit Sortierung anstelle von List aus.

Vermeiden Sie generische Implementierungen mit Reflektion, wenn dies möglich ist. Dies kann ebenfalls zu Leistungsproblemen führen.

0
user3285954