Скажем, у меня есть список объектов:
var items = new {
new { Order = 0 },
new { Order = 1 },
new { Order = -1 },
new { Order = 3 },
new { Order = 2 },
new { Order = -1 }
};
Я должен заказать его так, чтобы объекты с Order > -1
будьте сверху списка, заказанного возрастанием Порядка и остающимися объектами с Order == -1
следовали за ними.
Есть ли более изящный способ сделать это, чем использование Conact()
и Where()
пункты:
var orderedItems = items.Where(x => x.Order > -1).OrderBy(x => x.Order)
.Conact(items.Where(x => x.Order == -1);
Так, чтобы после сортировки этого списка был бы похож:
var items = new {
new { Order = 0 },
new { Order = 1 },
new { Order = 2 },
new { Order = 3 },
new { Order = -1 },
new { Order = -1 }
};
Также items
список в фактическом сценарии уже является комплексом IQueryable<T>
объект. Вот почему я пытаюсь найти самый оптимальный способ сделать такое выборочное упорядочивание.
Вы можете попробовать следующее - это даст ожидаемый результат:
items.OrderBy(x.Order => x.Order == -1).ThenBy(x.Order => x.Order);
Если вы упорядочиваете по возрастанию, -1 уже должно быть вверху списка, потому что это наименьшее значение.
Однако в более общем плане, если вы все еще хотите применить другую сортировку к подмножествам данных, я не думаю, что было бы более элегантный способ, потому что это именно то, что вы делаете, и объединение логически точное. Вы пытаетесь извлечь два отдельных подмножества данных, отсортировать их по-разному, а затем объединить их вместе, что является одной из вещей, для которых я должен использовать объединение.
Как отметил Майк, в вашем примере это будет работать автоматически, но, скажем, мы хотим сначала получить все -1 элементы, а затем отсортировать оставшиеся элементы в порядке убывания. Это можно сделать с помощью одного замечательного трюка. Вы можете использовать несколько ключей при упорядочивании элементов. Первым ключом может быть булево значение, которое будет false
для всех значений -1 (поэтому они будут первыми) и true
для всех остальных значений (поэтому они не будут переупорядочены). Вторым ключом может быть любое значение, которым вы хотите упорядочить оставшиеся элементы. Например:
var nums = new int[] { -1, 4, 2, 3, -1, 4, 7 };
var q = from n in nums
orderby n != -1, n descending
select n;
Сначала будут получены все значения, для которых n != -1
и false
, а затем все элементы, упорядоченные с помощью n по убыванию
, так что вы получите:
-1, -1, 7, 4, 4, 3, 2
Это работает в общем случае, когда вам нужно обрабатывать некоторые элементы особенно в упорядочении - вам просто нужно предоставить правильные ключи упорядочения.
Используйте настраиваемый компаратор , чтобы определить желаемый порядок.
public class MyComparer : IComparer<int>
{
public int Compare(int a, int b)
{
if ((a < 0) && (b >= 0))
{
return 1;
}
if ((a >= 0) && (b < 0))
{
return -1;
}
return int.Compare(a, b);
}
}
Тогда вы можете сделать:
var orderedItems = items.OrderBy(x => x.Order, new MyComparer());
Также здесь можно использовать настраиваемый компаратор, если вы хотите, чтобы -1 отображался первым, а остальные должны быть по убыванию , но почему-то я считаю его более элегантным :) Обратите внимание, что он сделан для ints
class Comparer : IComparer<int>
{
public int Compare(int x, int y)
{
if (x == -1 || y == -1) return x - y;
return y - x;
}
}
OrderBy(x => x.Order < 0 ? int.MaxValue : x.Order)
или, если вам нужно упорядочить отрицательные значения в порядке убывания
OrderBy(x => x.Order < 0 ? (long)int.MaxValue - x.Order : (long)x.Order)