2010-07-02 84 views
15

我需要在內存中按升序或降序排序字符串或數字。但是,列表可以包含空值,並且所有空值必須出現在數字或字符串後面。如何在LINQ中進行自定義排序,並始終使用null?

即輸入數據可能是:

1, 100, null, 5, 32.3

上升的結果將是

1, 5, 32.3, 100, null

的下降清單將是

100, 32.3, 5, 1, null

如何使這個任何想法工作?

回答

6

你可以編寫你自己的比較器,它代表一個現有的比較器,用於非空值,但總是在最後排序空值。事情是這樣的:

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排序實現,實際上依賴於這一點,但它絕對值得意識到的

+0

這不是對.NET排序實現的違約嗎?我認爲我已經閱讀過某些地方,排序方法可以假定null先來...或者...? – 2010-07-02 06:33:40

+0

@Lasse:這是對'IComparer '界面的違反,是的 - 我會編輯我的帖子來提到這一點。 – 2010-07-02 06:35:12

+0

是的,但是從我從記憶中得知的情況來看,這聽起來像是由於這個契約,排序方法可能帶有捷徑,因此在某些情況下實際上不會調用比較方法,因爲它「已經知道」結果是什麼將。換句話說,在某些情況下,這不會產生時髦的結果嗎? – 2010-07-02 06:36:26

38

我沒有在我面前一個編譯器檢查,但我想是這樣的:。

x.OrderBy(i => i == null).ThenBy(i => i) 
+3

尼斯...這是一個非常可愛的方法。如果我可以的話,我會多次投票... – 2010-07-02 06:38:53

+0

非常好。這種方法也適用於Linq-To-Entities並將其正確轉換爲Sql。 – 2015-05-06 17:01:05

0

正如喬恩說,你需要定義您的自定義比較器,實施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); 
    } 
相關問題