简体   繁体   English

如何自定义DataTable列的排序

[英]How can I customize the sorting of a DataTable column

I have a requirement to sort the values of a data table column. 我需要对数据表列的值进行排序。 That column contains strings, integers or mixed texts. 该列包含字符串,整数或混合文本。 For example: 例如:

The data table column contains values like this: 23, 18, 12, store 23, store a1, 1283, 25, ... 数据表列包含如下值: 23, 18, 12, store 23, store a1, 1283, 25, ...

If I sort the values by using Dataview.sort() method it results in this order: 12, 1283, 18, 23, 25, store 1283, store a1, ... but I need like this: 12, 18, 23, 25, 1283, store 23, store a1, ... 如果我使用Dataview.sort()方法对值进行排序,则会产生以下顺序: 12, 1283, 18, 23, 25, store 1283, store a1, ...但我需要这样: 12, 18, 23, 25, 1283, store 23, store a1, ...

Is there any simple method for attaining this requirement? 有没有简单的方法来达到这个要求?

I think you should use natural sorting and make your own IComparer 我认为你应该使用自然排序并制作自己的IComparer

The best algo I found was here 我找到的最好的算法就在这里

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

Just make it a generic class(as linq uses as Linq order by takes IComparer) , like following 只需将它设为泛型类(因为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;
        }


    }

Now to apply this, use linq 现在应用它,使用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;

Result 12, 23, 1283, store 1283 结果12,23,1283,商店1283

You can't directly according to your custom criteria. 您无法直接根据自定义条件。 You will have to write your own comparison code 您必须编写自己的比较代码

Take a look at this Question 看看这个问题

What is the datatype of the column. 列的数据类型是什么。 Data you posted is like alphanumeric ie, varchar 您发布的数据类似于字母数字,即varchar

You can sort the data in the datatable by using this line of code. 您可以使用此行代码对数据表中的数据进行排序。 Try this once. 试一试。

datatable.DefaultView.Sort = "COLUMN_NAME ASC"; 

If not Can you just rephrase your question specifying the datatype of the column because the column has both alphanumeric and numeric values. 如果不是,您是否可以重新定义指定列的数据类型的问题,因为该列具有字母数字和数字值。

The standard DB-level or DataView-type sort doesn't support mixed-type comparisons. 标准DB级或DataView类型排序不支持混合类型比较。

You could copy the rows from the original DataTable into an Array (such as with DataTable.Rows.CopyTo() , and then call Array.Sort() with a custom comparator. 您可以将原始DataTable的行复制到数组中(例如使用DataTable.Rows.CopyTo() ,然后使用自定义比较器调用Array.Sort()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM