如何排序整数字符串?

在使用整数值对字符串列表进行排序时,我遇到了一个奇怪的问题。 但是,某些值可能会以某些字符作为前缀。

例如

// B1, 5, 50, A10, 7, 72, B3, A1, A2 

基本上有页码,应按如下方式排序:

 // A1, A2, A10, B1, B3, 5, 7, 50, 72 

但是,如果我使用默认的字符串排序,那么这些将被排序为

 // A1, A10, A2, B1, B3, 5, 50, 7, 72 

在C#中有什么解决方案吗?

您正在寻找Alphanum算法 。 幸运的是,已经存在许多实现。 看到这里

这就是我为我们的应用程序解决它的方式,顺序就像在windows目录中一样:

 public class NaturalSortComparer : IComparer { public int Compare(string x, string y) { return StrCmpLogicalW(x, y); } [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] public static extern int StrCmpLogicalW(string x, string y); } 

用法:

  NaturalSortComparer comparer = new NaturalSortComparer(); return comparer.Compare(string1, string2); 

但它可能不完全是你想要的:

// A1,A2,A10,B1,B3,5,7,50,72

这会给

// 5,7,50,72,A1,A2,A10,B1,B3

您正在寻找的是自然排序。

杰夫阿特伍德曾在他的博客上发表了一篇很棒的文章,解释了这个概念,并用你可以采用的算法链接到其他各种来源。

人类排序:自然排序

这是一个自定义比较器,将按您所需的顺序排序。 请注意,此代码中没有错误/健全性检查:它假定所有字符串都采用正确的格式。

 public class MyComparer : IComparer { public int Compare(string x, string y) { Match xMatch = Regex.Match(x, @"^(\D*)(\d+)$"); Match yMatch = Regex.Match(y, @"^(\D*)(\d+)$"); string xChars = xMatch.Groups[1].Value; string yChars = yMatch.Groups[1].Value; if ((xChars.Length == 0) && (yChars.Length > 0)) { return 1; } else if ((xChars.Length > 0) && (yChars.Length == 0)) { return -1; } else { int charsResult = xChars.CompareTo(yChars); return (charsResult != 0) ? charsResult : int.Parse(xMatch.Groups[2].Value) .CompareTo(int.Parse(yMatch.Groups[2].Value)); } } } 

您可以像这样使用它:

 List testList = new List() { "B1","5","50","A10","7","72","B3","A1","A2" }; testList.Sort(new MyComparer()); // A1, A2, A10, B1, B3, 5, 7, 50, 72 

好吧,你总是可以调用Win32 API函数StrCmpLogicalW ,它完全符合你的要求(它是Explorer用来排序文件名的东西)。 唯一可能的缺点是排序不区分大小写。

不确定性能,并确保这可以优化,但它做的工作:

 string[] sort(string[] data) { return data .OrderBy(s => Regex.Match(s, @"^\D").Length == 0) .ThenBy(s => Regex.Match(s, @"\D*").Value) .ThenBy(s => Int32.Parse(Regex.Match(s, @"\d+").Value)).ToArray(); } var result = sort(new string[] { "B1", "5", "50", "A10", "7", "72", "B3", "A1", "A2" });