2014-01-21 43 views
2

我有多種類型的列表。類似於具有不同類型值的OrderBy列表

List<object> list = new List<object>() { 11.21, 323, 4, 3221, 221, 2, "asd" }; 
var qu = list.OrderBy((o) => o); 
qu.ToList().ForEach((e) => Console.WriteLine(e)); // throws exception 

拋出的異常是「對象必須是Int32類型。」

我該如何編寫Linq來排序這樣一個列表。

+0

你怎麼想的不同類型的項目進行排序?首先是:'11.21'還是'asd'? – MarcinJuraszek

+0

你如何決定訂單...? –

+0

我寧願將字符串排序在一起,並將double float int整合在一起。 –

回答

3
List<object> list = new List<object>() { 11.21, 323, 4, 3221, 221, 2, "asd" }; 
var qu = list.OrderBy((o) => o.ToString()); 
qu.ToList().ForEach((e) => Console.WriteLine(e)); 

您必須將您的項目投給某些內容,而不一定是int。在這個例子中,我將所有東西鑄造成字符串。請記住,OrderBy操作當然會按字符串排序而不是數字排序。由於列表中有一個字符串項目,因此不能按數字排序。

+1

它不會使用數字比較來訂購數字項目。 – MarcinJuraszek

+0

的確,我提到過。 –

3

這是我寫過最瘋狂的LINQ查詢之一...

var qu = list.Select(x => 
         { 
          decimal? d; 
          try 
          { 
           d = Convert.ToDecimal(x); 
          } 
          catch (FormatException) 
          { 
           d = null; 
          } 

          return new { v = x, d, s = x.ToString() }; 
         }).GroupBy(x => x.d.HasValue) 
          .Select(g => 
           g.Key 
           ? g.OrderBy(x => x.d.Value).Select(x => x.v) 
           : g.OrderBy(x => x.s).Select(x => x.v)) 
          .SelectMany(x => x) 
          .ToList(); 

返回所有數值第一,(使用它的價值排序),然後所有字符串使用標準的字符串比較排序。

2

我會用一個自定義比較:

o = o.OrderBy(x => x, new MyComparer()); 

...

internal class CustomComparer : IComparer<object> 
{ 
    public int Compare(object x, object y) 
    { 
     if (x is string && y is string) 
     { 
      return ((string)x).CompareTo((string)y); 
     } 
     else if (x is string && IsNumber(y)) 
     { 
      return -1; 
     } 
     else if (y is string && IsNumber(x)) 
     { 
      return 1; 
     } 
     else if (IsNumber(x) && IsNumber(y)) 
     { 
      return (Convert.ToDouble(x)).CompareTo(Convert.ToDouble(y)); 
     } 
     else 
     { 
      throw new NotSupportedException(); 
     } 
    } 

    private bool IsNumber(object o) 
    { 
     var t = o.GetType(); 
     if (o is int || o is double || o is float || o is long) 
      return true; 
     return false; 
    } 
} 
+1

你測試過了嗎?拆箱使用鑄造的''int'作爲'double'將不起作用。 – MarcinJuraszek

+0

@MarcinJuraszek好抓,固定 – Jack

0

如何實現IComparer<T>這樣嗎?

public class MyComparer : IComparer<object> 
{ 
    public int Compare(object x, object y) 
    { 
     var type = x.GetType(); 
     var type2 = y.GetType(); 
     if (type == typeof(string) && type2 == typeof(string)) 
     { 
      return String.Compare((string)x, (string)y); 
     } 
     else if (type.IsValueType && type2.IsValueType) 
     { 
      var comp = Comparer<double>.Default; 
      return comp.Compare(Convert.ToDouble(x), Convert.ToDouble(y)); 
     } 
     else 
     { 
      return 0; 
     } 
    } 
} 

並使用它:

List<object> list = new List<object>() { 11.21, 323, 4, 3221, 221, 2, "asd" }; 
var qu = list.OrderBy(o => o, new MyComparer()); 
qu.ToList().ForEach((e) => Console.WriteLine(e));