за зростанням / за спаданням в LINQ - чи можна змінити порядок за допомогою параметра?


77

У мене є метод, який отримує параметр "bool sortAscending". Тепер я хочу використовувати LINQ для створення відсортованого списку залежно від цього параметра. Тоді я отримав це:

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

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

Як бачите, обидва запити відрізняються лише "за зростанням" відповідно. «низхідний». Я хотів би об’єднати обидва запити, але не знаю як. Хтось має відповідь?


Отже, ви хочете мати один запит, який може виконувати як зростання, так і спадання, залежно від значення bool sortAsvending? Це правильно.
Nathan W

Відповіді:


119

Ви можете легко створити власний метод розширення на IEnumerable або 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);
}

Так, ви втрачаєте можливість використовувати вираз запиту тут - але, чесно кажучи, я не думаю, що ви насправді в цьому випадку виграєте від виразу запиту. Вирази запитів чудово підходять для складних речей, але якщо ви виконуєте лише одну операцію, простіше просто поставити цю одну операцію:

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

4
Дякую за виправлення моєї дурості Марк :) (Це проблема з розміщенням повідомлення безпосередньо перед сном на обід ...)
Джон Скіт,

9
На цю публікацію відповіли та відредагували дві знаменитості SO.com
Johnny_D

чи не повинен один із OrderByWithDirections повернутися по зростанню?
Ctrl_Alt_Defeat

1
@KOL: Я не впевнений, що ти маєш на увазі. Обидва вони повернуться по зростанню, якщо ви пройдете falseза descending.
Джон Скіт

@JonSkeet, дякую за рішення, але я розмістив запитання щодо його використання. см: stackoverflow.com/questions/18348767 / ...
ekkis

42

Що стосується того, як це реалізовано, це змінює метод - від OrderBy / ThenBy до OrderByDescending / ThenByDescending. Однак ви можете застосувати сортування окремо до основного запиту ...

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

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

Будь-яке використання? Ви можете динамічно створювати весь "замовлення", але він більше задіяний ...

Інший фокус (головним чином доречний для LINQ-to-Objects) полягає у використанні множника -1/1. Це дійсно корисно лише для числових даних, але це зухвалий спосіб досягнення того самого результату.


1
Я якраз збирався написати це саме те саме, тоді мій VS завмер :(
Nathan W

1
Використання множника також не вдається повернути значення int.MinValue.
Джон Скіт,

чому ви використовуєте метод orderBy-замість того, щоб використовувати ключове слово orderby у запиті linq?
Джошіт,

@Joshit, тому що мені потрібно робити різні операції в обох випадках, і немає ніякої вигоди від використання синтаксису запиту LINQ тут, ніж просто використання методу розширення. Якщо ви віддаєте перевагу синтаксису запиту: виконайте це, це буде добре.
Марк Гравелл

@MarcGravell велике спасибі за швидку відповідь !! Я думав, якщо два корифеї програмування продуктивності роблять це так, варто запитати, чи є якісь глибші причини;)
Джошіт,

8

А як щодо замовлення desc за бажаною властивістю,

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

А потім робити щось на зразок

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

Це зворотний () занадто повільно?


Мабуть, не найоптимізованіший, але, безумовно, дуже розумний підхід
Дієго Пенья

@DiegoPenha гул, але у випадку, якщо це було посилання на сутності до матеріалізації даних, має бути однаковим, чи не так? Я маю на увазі відповідний запит sql. Ви згодні?
гсубіран

@DiegoPenha забудь, посилання на сутності не підтримує функцію .Reverse () 😪
gsubiran

3

На додаток до прекрасного рішення, наданого @Jon Skeet, мені також знадобилися ThenBy та ThenByDescending, тому я додаю його на основі його рішення:

    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);
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.