使用LINQ进行字母数字排序

san*_*ngh 35 c# linq sorting

我有一个string[],其中每个元素都以一些数字值结尾.

string[] partNumbers = new string[] 
{ 
    "ABC10", "ABC1","ABC2", "ABC11","ABC10", "AB1", "AB2", "Ab11" 
};
Run Code Online (Sandbox Code Playgroud)

我试图按如下方式对上面的数组进行排序,LINQ但我没有得到预期的结果.

var result = partNumbers.OrderBy(x => x);
Run Code Online (Sandbox Code Playgroud)

实际结果:

AB1
Ab11
AB2
ABC1
ABC10
ABC10
ABC11
ABC2

预期结果

AB1
AB2
AB11
..

Nat*_*han 47

这是因为字符串的默认排序是标准字母数字字典(词典)排序,ABC11将在ABC2之前,因为排序总是从左到右进行.

要获得您想要的内容,您需要在order by子句中填充数字部分,例如:

 var result = partNumbers.OrderBy(x => PadNumbers(x));
Run Code Online (Sandbox Code Playgroud)

哪里PadNumbers可以定义为:

public static string PadNumbers(string input)
{
    return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10, '0'));
}
Run Code Online (Sandbox Code Playgroud)

对于输入字符串中出现的任何数字(或数字),这将填充零,以便OrderBy看到:

ABC0000000010
ABC0000000001
...
AB0000000011
Run Code Online (Sandbox Code Playgroud)

填充仅发生在用于比较的密钥上.原始字符串(没有填充)将保留在结果中.

请注意,此方法假定输入中的数字的最大位数.

  • @geek:该名称没有预定义的功能.我建议你用我描述的行为实现一个函数,使用正则表达式或一些这样的方法.功能名称仅用于说明目的. (3认同)
  • 我继续添加了一个简单的函数来进行填充。 (3认同)
  • 这节省了我的时间 (3认同)
  • 最后一个简短的解决方案。这非常有效,非常感谢! (2认同)

ran*_*uwe 9

Dave Koelle的网站上可以找到"正常工作"的字母数字排序方法的正确实现.在C#版本在这里.


Joh*_*yer 6

如果要使用LINQ和自定义比较器(如Dave Koelle的自定义比较器)按特定属性对对象列表进行排序,则应执行以下操作:

...

items = items.OrderBy(x => x.property, new AlphanumComparator()).ToList();

...
Run Code Online (Sandbox Code Playgroud)

您还必须更改Dave的类以从其继承,System.Collections.Generic.IComparer<object>而不是基本继承,IComparer因此类签名变为:

...

public class AlphanumComparator : System.Collections.Generic.IComparer<object>
{

    ...
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我更喜欢James McCormack的实现,因为它实现了IDisposable,尽管我的基准测试表明它稍慢一些。


Ale*_*kiy 5

您可以使用PInvoke获得快速而良好的结果:

class AlphanumericComparer : IComparer<string>
{
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    static extern int StrCmpLogicalW(string s1, string s2);

    public int Compare(string x, string y) => StrCmpLogicalW(x, y);
}
Run Code Online (Sandbox Code Playgroud)

您可以像AlphanumComparatorFast上面的答案一样使用它。