Question Comment trier une liste par une propriété dans l'objet


J'ai une classe appelée Order qui a des propriétés telles que OrderId, OrderDate, Quantity, et Total. J'ai une liste de ceci Order classe:

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

Maintenant, je veux trier la liste en fonction d'une propriété de la Order objet, par exemple j'ai besoin de le trier par la date de la commande ou l'identifiant de la commande.

Comment puis-je faire cela en C #?


902
2017-07-22 13:13


origine


Réponses:


La façon la plus simple de penser est d'utiliser Linq:

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

1328
2017-07-22 13:16



Si vous devez trier la liste sur place, vous pouvez utiliser le Sort méthode, en passant un Comparison<T> déléguer:

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

Si vous préférez créer une nouvelle séquence triée plutôt que de trier sur place, vous pouvez utiliser LINQ OrderBy méthode, comme mentionné dans les autres réponses.


501
2017-07-22 13:23



Pour ce faire sans LINQ sur .Net2.0:

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

Si vous êtes sur .Net3.0, alors LukeH's répondre c'est ce que vous cherchez.

Pour trier sur plusieurs propriétés, vous pouvez toujours le faire dans un délégué. Par exemple:

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

Cela vous donnerait Ascendant dates avec descendant orderIds.

Cependant, je ne recommanderais pas de coller des délégués car cela signifiera beaucoup d'endroits sans réutilisation de code. Vous devriez mettre en place un IComparer et juste passer à travers à votre Sort méthode. Voir ici.

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

Ensuite, pour utiliser cette classe IComparer, instanciez-la et transmettez-la à votre méthode Sort:

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

197
2017-07-22 13:35



Le moyen le plus simple de commander une liste est d'utiliser OrderBy

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

Si vous souhaitez commander par plusieurs colonnes comme suit SQL Query.

ORDER BY OrderDate, OrderId

Pour y parvenir, vous pouvez utiliser ThenBy comme suit.

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

76
2017-07-22 13:23



Le faire sans Linq comme vous l'avez dit:

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

Ensuite, appelez .sort () sur votre liste de commandes


31
2017-07-22 13:55



Une solution orientée objet classique

D'abord, je dois faire une génuflexion à l'awesomeness de LINQ .... Maintenant que nous avons cela à l'écart

Une variation sur la réponse de JimmyHoffa. Avec les génériques CompareTo Le paramètre devient type safe.

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

Ce tri par défaut est réutilisable bien sûr. Cela signifie que chaque client n'a pas besoin de réécrire de manière redondante la logique de tri. L'échange de "1" et "-1" (ou des opérateurs logiques, au choix) inverse l'ordre de tri.


19
2017-10-16 14:03



// Tri totalement générique à utiliser avec un 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);
    }

15
2018-06-13 01:37



Voici une méthode d'extension LINQ générique qui ne crée pas de copie supplémentaire de la liste:

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

Pour l'utiliser:

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

J'ai récemment construit ce supplémentaire qui accepte un ICompare<U>, afin que vous puissiez personnaliser la comparaison. Cela s'est avéré utile quand j'avais besoin de faire une sorte de chaîne naturelle:

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

5
2018-02-14 14:25



Utiliser LINQ

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

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

3
2017-07-22 13:16