我需要在內存中按升序或降序排序字符串或數字。但是,列表可以包含空值,並且所有空值必須出現在數字或字符串後面。如何在LINQ中進行自定義排序,並始終使用null?
即輸入數據可能是:
1, 100, null, 5, 32.3
上升的結果將是
1, 5, 32.3, 100, null
的下降清單將是
100, 32.3, 5, 1, null
如何使這個任何想法工作?
我需要在內存中按升序或降序排序字符串或數字。但是,列表可以包含空值,並且所有空值必須出現在數字或字符串後面。如何在LINQ中進行自定義排序,並始終使用null?
即輸入數據可能是:
1, 100, null, 5, 32.3
上升的結果將是
1, 5, 32.3, 100, null
的下降清單將是
100, 32.3, 5, 1, null
如何使這個任何想法工作?
你可以編寫你自己的比較器,它代表一個現有的比較器,用於非空值,但總是在最後排序空值。事情是這樣的:
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排序實現,實際上依賴於這一點,但它絕對值得意識到的
我沒有在我面前一個編譯器檢查,但我想是這樣的:。
x.OrderBy(i => i == null).ThenBy(i => i)
尼斯...這是一個非常可愛的方法。如果我可以的話,我會多次投票... – 2010-07-02 06:38:53
非常好。這種方法也適用於Linq-To-Entities並將其正確轉換爲Sql。 – 2015-05-06 17:01:05
正如喬恩說,你需要定義您的自定義比較器,實施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);
}
這不是對.NET排序實現的違約嗎?我認爲我已經閱讀過某些地方,排序方法可以假定null先來...或者...? – 2010-07-02 06:33:40
@Lasse:這是對'IComparer'界面的違反,是的 - 我會編輯我的帖子來提到這一點。 –
2010-07-02 06:35:12
是的,但是從我從記憶中得知的情況來看,這聽起來像是由於這個契約,排序方法可能帶有捷徑,因此在某些情況下實際上不會調用比較方法,因爲它「已經知道」結果是什麼將。換句話說,在某些情況下,這不會產生時髦的結果嗎? – 2010-07-02 06:36:26