2012-01-02 513 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()使用自定义比较。