Как стать автором
Обновить

Комментарии 9

повторный вызов метода OrderBy сбрасывает результат предыдущей сортировки

Всё-таки "сбрасывает" - не совсем корректное описание. Первая сортировка всё равно выполняется, просто после нее заново выполняется и вторая сортировка (в Вашем же примере первый и предпоследний элемент ведь поменялись местами именно по критерию возрастания поля Primary, при равных значениях поля Secondary = 2)

Термин "сбрасывает" может ввести кого-то в заблуждение о том, что первая сортировка выполняться не будет вовсе.

Разве OrderBy(...).OrderBy(...) - это паттерн ошибки?

OrderBy совершает устойчивую сортировку, т.е. не меняет относительное положение в последовательности при совпадении ключа. В итоге при двух OrderBy сначала будет проведена сортировка по первому ключу, а после, сортировка по второму и при этом относительный порядок первой сортировки сохранится.

У ThenBy отличие в том, что она совершает сортировку внутри ключа от предыдущей сортировки.

К примеру, взять второй пример из Unity. Там сначала сортировка идёт по priority, а после по наличию provider. В итоге такой сортировки получается, что сначала стоят элементы без provider, а после - с provider. При этом, в каждой из групп элементы отсортированы по priority.

Я не знаю, что делает данный код, но такая группировка по provider с последующей сортировкой "по весу" очень похоже на что-то вполне рабочее...

Чтобы получить аналогичный результат с ThenBy, нужно вообще говоря вызовы поменять местами:

.OrderBy(s => string.IsNullOrEmpty(s.provider)).ThenBy(s => s.priority)

Если простыми словами описывать, OrderBy().ThenBy() - это своего рода группировка по первому ключу с последующей сортировкой по этому ключу, а потом с сортировкой по второму ключу внутри группы.

Аналогия такая, если я правильно помню вызовы:

.GroupBy(s => string.IsNullOrEmpty(s.provider)).OrderBy(g => g.Key).SelectMany(g => g.OrderBy(s => s.priority))

P.S. Извиняюсь, не туда...

Не знаю кто вас минуснул. Говорить о том что баг есть - действительно преждевременно. Сортировка стабильная, значит несколько OrderBy подряд - вполне легальная ситуация. Конечно, это не так хорошо читается как ThenBy, т.к. работает "в обратном" порядке.

Отличный комментарий! Поставил плюс.

Пожалуй, немного подредактирую текст.

При этом мне кажется, что во втором примере из Unity как раз была бы понятнее последовательность вызовов OrderBy().ThenBy(). Да и в целом мне кажется, что такой код вызывает меньше вопросов. ? Как считаете?

В итоге такой сортировки получается, что сначала стоят элементы без provider, а после - с provider.

Просто для протокола - наоборот. Сначала будут идти элементы c provider, т.к. IsNullOrEmpty даст для них false.

Когда-то давно я не знал про ThenBy и сортировку по 2 ключам делал через два OrderBy.
Скорее всего, вариант с ThenBy более производительный, поэтому рекомендуемый.

Сообщение PVS-studio «Original sorting order will be lost» ошибочно, вот его точно надо переработать.

Взяли на карандаш.

Полностью согласен. ThenBy проще воспринимается, особенно, когда ты в мыслях у себя читаешь код: "сначала отсротировать по..., затем по...".

Я и сам, если так подумать, никогда двух OrderBy не писал, как раз из-за того, что оно тупо в мыслях нечитаемо. Но два OrderBy - всё равно рабочий вариант, хотя и не очевидный.

Спасибо, немного поправил текст в том месте.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий