Linq, операції orderby і orderbydescending

Операції упорядкування дозволяють вибудовувати вхідні послідовності в певному порядку. Важливо відзначити, що і OrderBy, і OrderByDescending вимагають вхідної послідовності типу IEnumerable і повертають послідовність типу IOrderedEnumerable. Передавати операціями OrderBy і OrderByDescending як вхідний послідовності IOrderedEnumerable не можна. Причина в тому, що наступні виклики операцій OrderBy і OrderByDescending не приймають до уваги порядок, створений попередніми викликами OrderBy і OrderByDescending. Це означає, що передавати послідовність, повернуту з OrderBy або OrderByDescending, в наступний виклик операції OrderBy або OrderByDescending не має сенсу.

Якщо потрібна велика ступінь упорядкування, ніж можливо досягти за допомогою одиночного виклику операції OrderBy або OrderByDescending, необхідно послідовно викликати операції ThenBy або ThenByDescending, мова про які піде в наступній статті.

Операція OrderBy дозволяє впорядкувати вхідну послідовність на основі методу keySelector. який повертає значення ключа для кожного вхідного елемента. Упорядкована вихідна послідовність IOrderedEnumerable видається в порядку зростання на основі значень повернутих ключів.

Сортування, виконана операцією OrderBy, визначена як нестійка. Це означає, що вона не зберігає вхідний порядок елементів. Якщо два вхідних елемента надходять в операцію OrderBy в певному порядку, і значення ключів цих двох елементів збігаються, їх розташування в вихідний послідовності може залишитися незмінним або помінятися, причому ні те, ні інше не гарантується. Навіть якщо все виглядає нормально, оскільки порядок визначено як нестійкий, завжди слід виходити з цього. Це означає, що ніколи не можна покладатися на порядок елементів, що надходять з операцій OrderBy або OrderByDescending, для будь-якого поля крім зазначеного у виклику методу. Збереження будь-якого порядку, який існує в послідовності, що передається будь-який з цих операцій, не може гарантуватися.

Операція OrderBy має два прототипи, описані нижче:

Перший прототип OrderBy

У цьому прототипі операції OrderBy передається вхідна послідовність source і делегат методу keySelector, а повертається об'єкт, який при перерахуванні проходить вхідні колекцію source, збираючи всі елементи і передаючи кожен з них методу keySelector, таким чином, отримуючи кожен ключ і впорядковуючи послідовність на основі цих ключів .

Методу keySelector отримує вхідний елемент типу T і повертає поле всередині елемента, яке використовується в якості значення ключа типу К для цього вхідного елемента. Типи До і T можуть бути однаковими або різними. Тип значення, повернутого методом keySelector, повинен реалізовувати інтерфейс IComparable.

Другий прототип OrderBy

Цей прототип такої ж, як перший, за винятком того, що він дозволяє передавати об'єкт-компаратор. Якщо використовується ця версія операції OrderBy, то немає необхідності в тому, щоб тип K реалізовував інтерфейс IComparable.

У наступному коді показаний приклад виклику першого прототипу:

Код в цьому прикладі впорядковує список машин по довжині їх назви. Результат виглядає наступним чином:

Linq, операції orderby і orderbydescending

Тепер спробуємо приклад другого прототипу з використанням власного компаратора. Перш ніж продемонструвати код, варто поглянути на інтерфейс IComparer.

Інтерфейс IComparer вимагає реалізації єдиного методу по імені Compare. Цей метод приймає два аргументи одного і того ж типу T і повертає значення int більше нуля, якщо перший аргумент більше другого, нуль - якщо аргументи еквівалентні, і значення менше нуля - якщо перший аргумент менше другого. Зверніть увагу, наскільки в цьому інтерфейсі і прототипі корисні узагальнення C #.

У цьому прикладі для ясності будь-якої компаратор за замовчуванням не використовується. Просто створюється клас, який реалізує інтерфейс IComparer, який впорядковує елементи на основі співвідношення голосних і приголосних:

Цей клас містить два методу - Compare і GetVowelConstantCount. Метод Compare потрібно інтерфейсом IComparer. Метод GetVowelConstantCount необхідний для внутрішнього використання в Compare і дозволяє отримати кількість голосних і приголосних у вхідному рядку. Також потрібна можливість викликати ту ж логіку за межами методу Compare, щоб можна було отримувати значення для відображення при проході циклом по впорядкованої послідовності.

Що конкретно робить компаратор - не настільки важливо. Дуже малоймовірно, що коли-небудь знадобиться визначати співвідношення голосних і приголосних в рядку, і ще менш ймовірно, що доведеться порівнювати два рядки на основі цього співвідношення. Більш важливим є те, як був створений клас, який реалізує інтерфейс IComparer за рахунок реалізації методу Compare. Тут можна спостерігати звичайну реалізацію методу Compare в блоці if / else в кінці методу. Як бачите, в цьому блоці коду повертається -1, 1 або О, що вимагає контракт інтерфейсу IComparer.

Тепер можна використовувати цей код:

Перед викликом операції OrderBy створюється екземпляр компаратора. Його екземпляр можна було б створити в самому виклику методу OrderBy, але тоді не вийшло б посилатися на нього в циклі foreach. Нижче показані результати запуску прикладу:

Linq, операції orderby і orderbydescending

Як бачите, елементи з меншим співвідношенням голосних і приголосних, виводяться першими.

OrderByDescending

Ця операції прототіпірована і поводиться подібно операції OrderBy, але з тією відмінністю, що впорядковує по спадаючій. Нижче показаний приклад використання даної операції:

Як бачите, назви машин розташовуються в порядку спаданням:

Linq, операції orderby і orderbydescending