82 votes

ascendant/descendant dans LINQ - peut-on changer l'ordre via un paramètre ?

J'ai une méthode qui reçoit le paramètre "bool sortAscending". Je veux maintenant utiliser LINQ pour créer une liste triée en fonction de ce paramètre. J'obtiens alors ceci :

var ascendingQuery = from data in dataList
                      orderby data.Property ascending
                      select data;

var descendingQuery = from data in dataList
                      orderby data.Property descending
                      select data;

Comme vous pouvez le constater, les deux requêtes ne diffèrent que par l'ordre "ascendant" ou "descendant". J'aimerais fusionner les deux requêtes, mais je ne sais pas comment. Quelqu'un a-t-il la réponse ?

0 votes

Vous voulez donc avoir une requête qui peut être ascendante ou descendante en fonction de la valeur de bool sortAsvending ? Est-ce exact ?

120voto

Jon Skeet Points 692016

Vous pouvez facilement créer votre propre méthode d'extension sur IEnumerable ou IQueryable :

public static IOrderedEnumerable<TSource> OrderByWithDirection<TSource,TKey>
    (this IEnumerable<TSource> source,
     Func<TSource, TKey> keySelector,
     bool descending)
{
    return descending ? source.OrderByDescending(keySelector)
                      : source.OrderBy(keySelector);
}

public static IOrderedQueryable<TSource> OrderByWithDirection<TSource,TKey>
    (this IQueryable<TSource> source,
     Expression<Func<TSource, TKey>> keySelector,
     bool descending)
{
    return descending ? source.OrderByDescending(keySelector)
                      : source.OrderBy(keySelector);
}

Oui, vous perdez ici la possibilité d'utiliser une expression de requête - mais franchement, je ne pense pas que vous bénéficiez réellement d'une expression de requête dans ce cas. Les expressions de requête sont parfaites pour les choses complexes, mais si vous ne faites qu'une seule opération, il est plus simple de ne mettre que cette seule opération :

var query = dataList.OrderByWithDirection(x => x.Property, direction);

4 votes

Merci d'avoir corrigé ma stupidité Marc :) (C'est le problème de poster juste avant d'aller déjeuner...)

9 votes

Cet article a été répondu et édité par deux célébrités de SO.com.

0 votes

L'un des OrderByWithDirections ne devrait-il pas renvoyer une valeur ascendante ?

43voto

Marc Gravell Points 482669

Pour ce qui est de la mise en œuvre, cela modifie le système de gestion de l'information de l'UE. méthode - de OrderBy/ThenBy à OrderByDescending/ThenByDescending. Cependant, vous pouvez appliquer le tri séparément à la requête principale...

var qry = from .... // or just dataList.AsEnumerable()/AsQueryable()

if(sortAscending) {
    qry = qry.OrderBy(x=>x.Property);
} else {
    qry = qry.OrderByDescending(x=>x.Property);
}

Utilisation ? Vous pouvez créer l'ensemble de la "commande" de manière dynamique, mais c'est plus compliqué...

Une autre astuce (principalement adaptée à LINQ-to-Objects) consiste à utiliser un multiplicateur de -1/1. Cela n'est vraiment utile que pour les données numériques, mais c'est une façon insolente d'obtenir le même résultat.

1 votes

J'étais sur le point d'écrire exactement la même chose, puis mon VS s'est figé :(

1 votes

L'utilisation d'un multiplicateur échoue également pour une valeur de retour de int.MinValue.

0 votes

Pourquoi utilise-t-on la méthode orderBy au lieu d'utiliser le mot-clé orderby dans une requête linq ?

8voto

sports Points 510

Pourquoi ne pas classer les desc en fonction de la propriété souhaitée ?

   blah = blah.OrderByDescending(x => x.Property);

Et ensuite, en faisant quelque chose comme

  if (!descending)
  {
       blah = blah.Reverse()
  }
  else
  {
      // Already sorted desc ;)
  }

La fonction Reverse() est-elle trop lente ?

0 votes

Ce n'est probablement pas la solution la plus optimisée, mais c'est une approche très intelligente.

0 votes

@DiegoPenha humm mais si c'était linq to entities avant de matérialiser les données, cela devrait être la même chose, non ? Je veux dire qu'il produira une requête sql en conséquence. Vous êtes d'accord ?

0 votes

@DiegoPenha oublie ça, linq to entities ne supporte pas la fonction .Reverse()

4voto

ehh Points 552

En plus de la belle solution donnée par @Jon Skeet, j'avais aussi besoin de ThenBy et ThenByDescending, donc je l'ajoute en me basant sur sa solution :

    public static IOrderedEnumerable<TSource> ThenByWithDirection<TSource, TKey>(
         this IOrderedEnumerable<TSource> source, 
         Func<TSource, TKey> keySelector,  
         bool descending)
    {
        return descending ? 
               source.ThenByDescending(keySelector) :
               source.ThenBy(keySelector);
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X