2012-01-02 519 views
1

我有一個要求對數據表列的值進行排序的要求。該列包含字符串,整數或混合文本。例如:如何自定義DataTable列的排序

數據表列中包含這樣的值:23, 18, 12, store 23, store a1, 1283, 25, ...

如果我的價值觀通過Dataview.sort()方法它會導致這個順序進行排序:12, 1283, 18, 23, 25, store 1283, store a1, ...但我需要這樣的:12, 18, 23, 25, 1283, store 23, store a1, ...

有任何簡單的方法來達到這個要求?

+0

你就不能下令將直接進入SQL?我認爲這將是最有效率的,因爲您不必重新獲取Dataview.sort()中的所有數據() – DonCallisto 2012-01-02 09:53:58

+0

此數據取自Sharepoint List。 – MAC 2012-01-02 09:57:22

回答

4

我認爲你應該使用自然排序,讓你自己的IComparer

我找到的最好的算法中在這裏

http://www.davekoelle.com/files/AlphanumComparator.cs

只是使其成爲一個通用類(如LINQ通過採用IComparer的使用LINQ的爲順序)像下面

public class AlphanumComparator<T> : IComparer<T> 
    { 
     private enum ChunkType { Alphanumeric, Numeric }; 
     private bool InChunk(char ch, char otherCh) 
     { 
      ChunkType type = ChunkType.Alphanumeric; 

      if (char.IsDigit(otherCh)) 
      { 
       type = ChunkType.Numeric; 
      } 

      if ((type == ChunkType.Alphanumeric && char.IsDigit(ch)) 
       || (type == ChunkType.Numeric && !char.IsDigit(ch))) 
      { 
       return false; 
      } 

      return true; 
     } 

     public int Compare(T x, T y) 
     { 
      String s1 = x as string; 
      String s2 = y as string; 
      if (s1 == null || s2 == null) 
      { 
       return 0; 
      } 

      int thisMarker = 0, thisNumericChunk = 0; 
      int thatMarker = 0, thatNumericChunk = 0; 

      while ((thisMarker < s1.Length) || (thatMarker < s2.Length)) 
      { 
       if (thisMarker >= s1.Length) 
       { 
        return -1; 
       } 
       else if (thatMarker >= s2.Length) 
       { 
        return 1; 
       } 
       char thisCh = s1[thisMarker]; 
       char thatCh = s2[thatMarker]; 

       StringBuilder thisChunk = new StringBuilder(); 
       StringBuilder thatChunk = new StringBuilder(); 

       while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || InChunk(thisCh, thisChunk[0]))) 
       { 
        thisChunk.Append(thisCh); 
        thisMarker++; 

        if (thisMarker < s1.Length) 
        { 
         thisCh = s1[thisMarker]; 
        } 
       } 

       while ((thatMarker < s2.Length) && (thatChunk.Length == 0 || InChunk(thatCh, thatChunk[0]))) 
       { 
        thatChunk.Append(thatCh); 
        thatMarker++; 

        if (thatMarker < s2.Length) 
        { 
         thatCh = s2[thatMarker]; 
        } 
       } 

       int result = 0; 
       // If both chunks contain numeric characters, sort them numerically 
       if (char.IsDigit(thisChunk[0]) && char.IsDigit(thatChunk[0])) 
       { 
        thisNumericChunk = Convert.ToInt32(thisChunk.ToString()); 
        thatNumericChunk = Convert.ToInt32(thatChunk.ToString()); 

        if (thisNumericChunk < thatNumericChunk) 
        { 
         result = -1; 
        } 

        if (thisNumericChunk > thatNumericChunk) 
        { 
         result = 1; 
        } 
       } 
       else 
       { 
        result = thisChunk.ToString().CompareTo(thatChunk.ToString()); 
       } 

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

      return 0; 
     } 


    } 

我們應用此,使用LINQ

DataTable dt = new DataTable(); 
      dt.TableName = "Sort"; 
      dt.Columns.Add("Check"); 
      DataRow dr = dt.NewRow(); 
      dr["Check"] = "12"; 
      dt.Rows.Add(dr); 

      DataRow dr2 = dt.NewRow(); 
      dr2["Check"] = "1283"; 
      dt.Rows.Add(dr2); 

      DataRow dr3 = dt.NewRow(); 
      dr3["Check"] = "store 1283"; 
      dt.Rows.Add(dr3); 

      DataRow dr4 = dt.NewRow(); 
      dr4["Check"] = "23"; 
      dt.Rows.Add(dr4); 

      DataView dv = new DataView(); 
      dv.Table = dt; 

      AlphanumComparator<string> comparer = new AlphanumComparator<string>(); 
      //DataTable dtNew = dv.Table; 
      DataTable dtNew = dv.Table.AsEnumerable().OrderBy(x => x.Field<string>("Check"), comparer).CopyToDataTable(); 
      dtNew.TableName = "NaturalSort"; 

      dv.Table = dtNew; 

結果12,23,1283,1283店

+0

它工作的很好..謝謝你Anand – MAC 2012-01-02 10:59:48

+0

這個版本和原始站點上的版本有一個錯誤,當數值塊溢出時Int32。該算法的原始方法是簡單地比較數字塊char char char,直到一個不同。錯誤是'Convert.ToInt32(thisChunk.ToString());' – 2012-09-09 17:53:22

1

您不能直接根據您的自定義標準。您必須編寫自己的代碼比較

看看這個Question

1

什麼是列的數據類型。您發佈的數據類似字母數字,即varchar

您可以使用這一行代碼對數據表中的數據進行排序。嘗試一次。

datatable.DefaultView.Sort = "COLUMN_NAME ASC"; 

如果不是你能改寫剛纔你的問題指定列的數據類型,因爲該列既有字母和數字的值。

+0

我曾試過這種方法.... – MAC 2012-01-02 10:04:29

+0

我們不能對混合類型數據進行排序。 – JayOnDotNet 2012-01-02 10:07:01

+0

嘗試在數據庫級別進行排序並將其添加到數據表後 – JayOnDotNet 2012-01-02 10:15:17

1

標準數據庫級或DataView類型的排序不支持混合類型比較。

你可以從原來的DataTable行復制到一個數組(如用DataTable.Rows.CopyTo(),然後調用Array.Sort()使用自定義比較。