2017-03-31 66 views
1

我想這個名單排序號碼,則字符串C#

A 
B 
C 
111 
11 
123 
1 
42 
5 

進行排序

1 
5 
11 
42 
111 
123 
A 
B 
C 

默認情況下,它像串(所以,它會1,11,111,123,42,5排序號碼), 但我想排序數字像數字,而不是數字的字符串。

是否有乾淨的解決方案來排序它像上面?

這是一個對象列表,而對象有幾個屬性,其中之一就是這個字符串。

+1

是您的列表,開始用什麼類型的?你已經嘗試了什麼? –

+0

你的數字是以字符串表示還是整數? – Amy

+0

https://stackoverflow.com/questions/119730/how-do-i-sort-a-varchar-column-in-sql-server-that-c​​ontains-numbers – mxmissile

回答

4

這對於大多數使用情況下工作,但如果字符串控制字符開頭可能有奇怪的結果,串像「\ TABC」會在整數前:

list.OrderBy(x=>int.TryParse(x, out var dummy) ? dummy.ToString("D10") : x); 

或C#的先前版本到7:

list.OrderBy(x=> { int dummy; return int.TryParse(x, out dummy) ? dummy.ToString("D10") : x;}); 
+2

你知道你可以做'dummy.ToString(「D10」)'而不是另一個解析。 – juharr

+1

@juharr更新的答案不需要兩個解析,並添加了C#7.0版本。 –

0

您可以遍歷所有值一次,並使用int.TryParse將它們分成兩個單獨的列表:一個用於int.TryParse返回true的值(又名數字),另一個列表用於其中的值返回false(非數字)。然後你可以分別對這兩個列表進行排序,並在最後連接它們的排序結果。

2

我寫了這個IComparer執行幾個月後回來處理這樣的事情。我認爲它會默認做你想做的事情,儘管它是爲處理更復雜的情況而設計的,其中數字/字母組由分隔符分隔,而分隔符也需要以原子方式分類。你應該能夠根據你的需求進行調整。

public class SemanticComparer : IComparer<string> 
{ 
    private static Regex _splitter = new Regex("\\W+"); 

    public int Compare(string x, string y) 
    { 
     string[] partsX = _splitter.Split(x); 
     string[] partsY = _splitter.Split(y); 

     int shortest = Math.Min(partsX.Length, partsY.Length); 

     for (int index = 0; index < shortest; index++) 
     { 
      int intX, intY; 
      int result; 

      if (int.TryParse(partsX[index], out intX) && int.TryParse(partsY[index], out intY)) 
      { 
       result = intX.CompareTo(intY); 
      } 
      else 
      { 
       result = string.Compare(partsX[index], partsY[index], StringComparison.Ordinal); 
      } 

      if (result != 0) 
      { 
       return result; 
      } 
     } 

     return 0; 
    } 
} 

您可以像這種用它列表:

MyList.Sort(new SemanticComparer()); 
2

你想要什麼叫Natural sort

我曾經寫了一些代碼:

public static class NaturalCompare 
{ 
    public static int Compare(string first, string second, StringComparison comparison = StringComparison.Ordinal) 
    { 
     if (string.Compare(first, second, comparison) == 0) 
     { 
      return 0; 
     } 

     if (first == null) 
     { 
      return -1; 
     } 

     if (second == null) 
     { 
      return 1; 
     } 

     DateTime d1, d2; 

     if (DateTime.TryParse(first, out d1) && DateTime.TryParse(second, out d2)) 
     { 
      return d1.CompareTo(d2); 
     } 

     var pos1 = 0; 
     var pos2 = 0; 

     int result; 
     do 
     { 
      bool isNum1, isNum2; 

      var part1 = GetNext(first, ref pos1, out isNum1); 
      var part2 = GetNext(second, ref pos2, out isNum2); 

      if (isNum1 && isNum2) 
      { 
       result = long.Parse(part1).CompareTo(long.Parse(part2)); 
      } 
      else 
      { 
       result = String.Compare(part1, part2, comparison); 
      } 
     } while (result == 0 && pos1 < first.Length && pos2 < second.Length); 

     return result; 
    } 

    public static int CompareToNatural(this string first, string second, StringComparison comparison = StringComparison.Ordinal) 
    { 
     return Compare(first, second, comparison); 
    } 

    public static IOrderedEnumerable<TSource> OrderByNatural<TSource>(this IEnumerable<TSource> source, Func<TSource, string> keySelector) 
    { 
     return source.OrderBy(keySelector, new NatComparer()); 
    } 

    public static IOrderedEnumerable<TSource> OrderByNaturalDescending<TSource>(this IEnumerable<TSource> source, Func<TSource, string> keySelector) 
    { 
     return source.OrderByDescending(keySelector, new NatComparer()); 
    } 

    private sealed class NatComparer : IComparer<string> 
    { 
     public int Compare(string x, string y) 
     { 
      return NaturalCompare.Compare(x, y); 
     } 
    } 

    private static string GetNext(string s, ref int index, out bool isNumber) 
    { 
     if (index >= s.Length) 
     { 
      isNumber = false; 
      return ""; 
     } 

     isNumber = char.IsDigit(s[index]); 

     var start = index; 
     while (index < s.Length && char.IsDigit(s[index]) == isNumber) 
     { 
      index++; 
     } 
     return s.Substring(start, index - start); 
    } 
} 
0

我沒有測試性能的代碼,但是你可以用的Comparer

public class ArrayItemComparer : IComparer<string> 
{ 
    public int Compare(string x, string y) 
    { 
     int xInt = 0, yInt = 0; 

     bool parseX = int.TryParse(x, out xInt); 
     bool parseY = int.TryParse(y, out yInt); 

     if (parseX && parseY) 
     { 
      return xInt.CompareTo(yInt); 
     } 
     else if (parseX) 
     { 
      return -1; 
     } 
     else if (parseY) 
     { 
      return 1; 
     } 
     else 
     { 
      return x.CompareTo(y); 
     } 
    } 
} 
0

我已經創建了一個解決方案解決了這個爲了這。我將list分爲兩部分,然後排序和連接。請檢查以下內容:

public List<ListItem> getSortedList() 
{ 
    int dummy = 0; 

    List<ListItem> list = new List<ListItem>(); 
    list.Add(new ListItem() { Item = "A" }); 
    list.Add(new ListItem() { Item = "B" }); 
    list.Add(new ListItem() { Item = "C" }); 
    list.Add(new ListItem() { Item = "111" }); 
    list.Add(new ListItem() { Item = "11" }); 
    list.Add(new ListItem() { Item = "123" }); 
    list.Add(new ListItem() { Item = "1" }); 
    list.Add(new ListItem() { Item = "42" }); 
    list.Add(new ListItem() { Item = "5" }); 

    var listNumber = list.Where(m => int.TryParse(m.Item, out dummy)).ToList().OrderBy(m => Convert.ToInt16(m.Item)).ToList(); 
    var listString = list.Where(m => !int.TryParse(m.Item, out dummy)).ToList().OrderBy(m => m.Item).ToList(); 

    var sortedList = listNumber.Concat(listString).ToList(); 

    return sortedList; 
} 

您可以在DotNetFiddle中運行此操作。

0

假設你開始字符串的集合,一個簡單的比較器應該做的工作:

public class Comparer : IComparer<string> 
{ 
    public int Compare(string a, string b) 
    { 
     int ia = 0; 
     int ib = 0; 
     var aIsInt = int.TryParse(a,out ia); 
     var bIsInt = int.TryParse(b,out ib); 
     if (aIsInt == bIsInt) 
     { 
      if (aIsInt) 
      { 
       return ia.CompareTo(ib); 
      } 
      else 
      { 
       return a.CompareTo(b); 
      } 
     } 
     return aIsInt ? -1 : 1; 
    } 
} 

Here's a fiddle