2010-10-03 88 views
6

我在linqtosql的查詢返回LabelNumber:C#LINQ的自定義排序

var q = from list in db.Lists 
     select list.LabelNumber; 

var q就變成像這樣元素的IEnumerable<string>

{"1","2","2.A","2.B","3","3.A","3.B"} 

我基本上要訂購的元素他們出現在上面,但我不能使用OrderBy(x=>x.LabelNumber),因爲"10"將被放置在"1"之後和"2"之前。

我假設我必須編寫一個自定義比較函數,但是如何使用linq來做到這一點?

編輯:我認爲以下所有答案都可以使用,但必須在所有回覆中添加一條警告。

如果您正在使用Linq2SQL,則不能在查詢中使用數組索引。爲了克服這個問題,你應該有兩個查詢。一個從SQL讀取。第二個廣告排序:

var q = from list in db.Lists 
      select list.LabelNumber; 

var q2 = q.AsEnumerable() 
      .OrderBy(x => int.Parse(x.LabelNumber.Split('.')[0])) 
      .ThenBy(x => x.Number 
         .Contains(".") ? 
           x.LabelNumber.Split('.')[1].ToString() 
           : 
           string.Empty); 
+0

僅供參考,按您想要的方式對數字進行排序稱爲「自然排序」。 – mquander 2010-10-03 04:44:41

回答

9

您可能沒有寫一個自定義比較。如果您的所有標籤均採用number.letter的形式,則可以使用該標籤。

如果您需要更多的控制,你總是可以轉換sortby場(ab)到合適的類型,而不是整數和字符串。


如果這是LINQ-to-SQL,這實際上不起作用,因爲這裏使用的某些方法不被支持。這是一個LINQ到SQL的友好版本。它不會產生最漂亮的查詢,但它會起作用。

var query = from list in db.Lists 
      let dot = list.LabelNumber.IndexOf('.') 
      let name = list.LabelNumber 
      let order = dot == -1 
       ? new { a = Convert.ToInt32(name.Substring(0, dot)), b = String.Empty } 
       : new { a = Convert.ToInt32(name.Substring(0, dot)), b = name.Substring(dot+1) } 
      orderby order.a, order.b 
      select list.LabelNumber; 
+0

我得到這個錯誤,當我運行這個:'System.InvalidOperationException:無法識別的表達式節點:ArrayIndex' – Shawn 2010-10-03 05:33:04

+0

這是在LINQ到SQL的權利?當然這不會在那裏工作,並需要一些調整。 – 2010-10-03 05:39:46

+0

我添加了一個編輯來解決調整問題。謝謝。 – Shawn 2010-10-03 05:58:12

1

如果您確信q格式正確和測序:

var result = q.OrderBy(x => int.Parse(x.Split('.')[0])); 
+2

你假設只有數字出現故障。如果你有2.B,2,2.A怎麼辦? – 2010-10-03 05:16:59

+0

@Michael:OP沒有說他想要按字母順序排列......而且我很懶。無論如何,這很可能是他想要的。大聲笑。 – 2010-10-03 05:23:13

11
OrderBy(x=>x.LabelNumber, new AlphanumComparator()) 

其中AlphanumComparator是由大衛Koelle優秀Alphanum natural sort algorithm。沒有必要重新發明輪子。

如果你要使用C#版本改變爲:

AlphanumComparator : IComparer<string> 

public int Compare(string x, string y) 
+3

+1,用於向我介紹AlphanumComparator – 2010-10-03 05:22:24

+0

此語法不起作用。 '參數3:無法從'AlphanumComparator'轉換爲'System.Collections.Generic.IComparer'' – Shawn 2010-10-03 05:22:49

+0

這是因爲OrderBy需要一個通用的IComparer,而AlphanumComparator是非通用的。雖然這個改變很容易做到。在聲明中加入,將所有對象改爲Ts並移除強制轉換。 – Kyte 2010-10-03 05:27:27

0

這裏是我的貢獻..使用Regular ExpressionLAMBDA expression

List<String> Lst = new List<string> { "1", "2", "2.A","10.A", "2.C", "3", "3.A", "3.B","2.B","11.D" }; 
Lst = Lst.Select(X => new 
     { 
      Number = int.Parse(Regex.Match(X, @"([0-9]*).?([a-zA-Z]*)").Groups[1].Value), 
      Strings=Regex.Match(X, @"([0-9]*).?([a-zA-Z]*)").Groups[2].Value, 
      OriginalString = X 
     }).OrderBy(X => X.Number).ThenBy(X=>X.Strings) 
     .Select(X => X.OriginalString).ToList(); 

輸出:

"1" 
"2" 
"2.A" 
"2.B" 
"2.C" 
"3" 
"3.A" 
"3.B" 
"10.A" 
"11.D" 
+0

'方法'System.Text.RegularExpressions.Match匹配(System.String,System.String)'沒有支持轉換爲SQL.'雖然它似乎在你的例子中工作。 – Shawn 2010-10-03 05:45:41

+0

然後用你的labelnumbers創建一個'list',然後用上面的表達式對它進行排序。 – 2010-10-03 05:51:06

+0

把它解決了。謝謝,我讓你用Linq2SQL運行代碼。我不知道陣列限制。我結束了使用更簡單的版本,因爲正則表達式使我的情況變得複雜。子嵌套最終會變得更復雜,我將不得不求助於你的解決方案。謝謝。 – Shawn 2010-10-03 06:00:57