Ответ 1
У меня нет компилятора передо мной, но я думаю что-то вроде:
x.OrderBy(i => i == null).ThenBy(i => i)
Мне нужно отсортировать по спискам строк или чисел в порядке возрастания или убывания. Однако список может содержать нулевые значения, и все нулевые значения должны появляться после чисел или строк.
То есть входные данные могут быть:
1, 100, null, 5, 32.3
Восходящий результат будет
1, 5, 32.3, 100, null
По убыванию будет
100, 32.3, 5, 1, null
Любые идеи о том, как сделать эту работу?
У меня нет компилятора передо мной, но я думаю что-то вроде:
x.OrderBy(i => i == null).ThenBy(i => i)
Вы можете написать свой собственный сопоставитель, который делегирует существующий для непустых, но всегда сортирует нули в конце. Что-то вроде этого:
public class NullsLastComparer<T> : IComparer<T>
{
private readonly IComparer<T> proxy;
public NullsLastComparer(IComparer<T> proxy)
{
this.proxy = proxy;
}
public override int Compare(T first, T second)
{
if (first == null && second == null)
{
return 0;
}
if (first == null)
{
return 1;
}
if (second == null)
{
return -1;
}
return proxy.Compare(first, second);
}
}
РЕДАКТИРОВАТЬ: Несколько вопросов с этим подходом:
Во-первых, он не играет хорошо с анонимными типами; вам может понадобиться отдельный метод расширения, чтобы это хорошо работало. Или используйте ответ Кена:)
Что еще более важно, он нарушает контракт IComparer<T>
, который указывает, что нули должны быть первыми. Теперь, лично, я думаю, что это ошибка в спецификации IComparer<T>
- возможно, это должно означать, что компаратор должен обрабатывать нули, но он не должен указывать, наступают ли они первым или последним... он делает такие требования (которые отлично разумно) невозможно выполнить так же чисто, как мы могли бы хотеть, и имеет всевозможные неудобные последствия для вещей, таких как реверсивный компаратор. Вы ожидали бы, что такая вещь полностью изменит порядок, но согласно спецификации она все равно должна поддерживать нули в начале: (
Я не думаю, что видел какие-либо реализации сортировки .NET, которые на самом деле полагаются на это, но это определенно стоит знать.
Как сказал Джон, вам нужно определить свой пользовательский Comparer, реализуя IComparer
. Вот как ваш метод Compare
в пользовательском сопоставлении хотел бы, чтобы он мог сохранить null
в конце.
public int Compare(Object x, Object y)
{
int retVal = 0;
IComparable valX = x as IComparable;
IComparable valY = y as IComparable;
if (valX == null && valY == null)
{
return 0;
}
if (valX == null)
{
return 1;
}
else if (valY == null)
{
return -1;
}
return valX.CompareTo(valY);
}