如何正确排序 DataTable 的字符串数字列
How to properly sort a string-number column of a DataTable
我正在尝试对字符串数字列进行排序,例如N1、N10、N100、N2,我期待结果 N1、N2、N10、N100,但排序不起作用,我以相同的顺序得到相同的值 N1、N10、N100、N2。
我写了下面的代码。
static class ExtensionMethod
{
public static DataTable SortAlphaNumeric(this DataTable datatable, string columnName)
{
return datatable.AsEnumerable()
.OrderBy(r => r.Field<String>(columnName), new CustomComparer())
.CopyToDataTable();
}
}
public class CustomComparer : IComparer<string>
{
public int Compare(string x, string y)
{
var numberX = Regex.Match(x, @"\d+").Value;
var numberY = Regex.Match(y, @"\d+").Value;
var alphaX = Regex.Match(x, @"[^a-z]").Value;
var alphaY = Regex.Match(y, @"[^a-z]").Value;
if (alphaX.CompareTo(alphaY) == 0)
return numberX.CompareTo(numberY);
else if (alphaX.CompareTo(alphaY) < 0)
return -1;
return 1;
}
}
// Code example
class TestExample
{
public void Test()
{
var dt = new DataTable();
dt.Columns.Add("AlphaNumeric", Type.GetType("System.String"));
var row = dt.NewRow();
row["AlphaNumeric"] = "N1";
dt.Rows.Add(row);
row = dt.NewRow();
row["AlphaNumeric"] = "N10";
dt.Rows.Add(row);
row = dt.NewRow();
row["AlphaNumeric"] = "N100";
dt.Rows.Add(row);
row = dt.NewRow();
row["AlphaNumeric"] = "N2";
dt.Rows.Add(row);
var orderedDt = dt.SortAlphaNumeric("AlphaNumeric");
}
}
我会使用 (?<alpha>[A-Za-z])(?<number>\d+)
作为正则表达式并比较 alpha
(字符串比较),然后,如果相等,int.Parse
和 number
并比较它(整数比较)。
这只会执行两次正则表达式而不是四次(可能编译正则表达式并将其放在静态字段中也会使其更快),并且 2
将小于 10
如果你比较实际数字。如果你不解析数字,你可以跳过整个正则表达式,只做一个字符串比较。
比较器的变化:
var numberX = int.Parse(Regex.Match(x, @"\d+").Value);
var numberY = int.Parse(Regex.Match(y, @"\d+").Value);
如果数字 sheme 是确定的(总是一个字符串 + 一个整数),您可以简单地将它们存储在两个单独的字段中(最好回到数据库中。组合键毕竟是一回事)。那么就是"sort by string first, number 2nd".
如果不是,事情就会变得艰难。您想要的是 Windows 对文件进行的非常不寻常的排序。除了自定义正则表达式解决方案(但同样,如果它是确定性的,您可以适当地使用 2 个或更多字段),还有 StrCmpLogicalW。但是那个是非托管的,它的行为在 Windows 之间变化(它是 "canonical" 排序它运行的 Windows,但排序在 Windows 版本之间变化)。
我正在尝试对字符串数字列进行排序,例如N1、N10、N100、N2,我期待结果 N1、N2、N10、N100,但排序不起作用,我以相同的顺序得到相同的值 N1、N10、N100、N2。
我写了下面的代码。
static class ExtensionMethod
{
public static DataTable SortAlphaNumeric(this DataTable datatable, string columnName)
{
return datatable.AsEnumerable()
.OrderBy(r => r.Field<String>(columnName), new CustomComparer())
.CopyToDataTable();
}
}
public class CustomComparer : IComparer<string>
{
public int Compare(string x, string y)
{
var numberX = Regex.Match(x, @"\d+").Value;
var numberY = Regex.Match(y, @"\d+").Value;
var alphaX = Regex.Match(x, @"[^a-z]").Value;
var alphaY = Regex.Match(y, @"[^a-z]").Value;
if (alphaX.CompareTo(alphaY) == 0)
return numberX.CompareTo(numberY);
else if (alphaX.CompareTo(alphaY) < 0)
return -1;
return 1;
}
}
// Code example
class TestExample
{
public void Test()
{
var dt = new DataTable();
dt.Columns.Add("AlphaNumeric", Type.GetType("System.String"));
var row = dt.NewRow();
row["AlphaNumeric"] = "N1";
dt.Rows.Add(row);
row = dt.NewRow();
row["AlphaNumeric"] = "N10";
dt.Rows.Add(row);
row = dt.NewRow();
row["AlphaNumeric"] = "N100";
dt.Rows.Add(row);
row = dt.NewRow();
row["AlphaNumeric"] = "N2";
dt.Rows.Add(row);
var orderedDt = dt.SortAlphaNumeric("AlphaNumeric");
}
}
我会使用 (?<alpha>[A-Za-z])(?<number>\d+)
作为正则表达式并比较 alpha
(字符串比较),然后,如果相等,int.Parse
和 number
并比较它(整数比较)。
这只会执行两次正则表达式而不是四次(可能编译正则表达式并将其放在静态字段中也会使其更快),并且 2
将小于 10
如果你比较实际数字。如果你不解析数字,你可以跳过整个正则表达式,只做一个字符串比较。
比较器的变化:
var numberX = int.Parse(Regex.Match(x, @"\d+").Value);
var numberY = int.Parse(Regex.Match(y, @"\d+").Value);
如果数字 sheme 是确定的(总是一个字符串 + 一个整数),您可以简单地将它们存储在两个单独的字段中(最好回到数据库中。组合键毕竟是一回事)。那么就是"sort by string first, number 2nd".
如果不是,事情就会变得艰难。您想要的是 Windows 对文件进行的非常不寻常的排序。除了自定义正则表达式解决方案(但同样,如果它是确定性的,您可以适当地使用 2 个或更多字段),还有 StrCmpLogicalW。但是那个是非托管的,它的行为在 Windows 之间变化(它是 "canonical" 排序它运行的 Windows,但排序在 Windows 版本之间变化)。