按数字排序数组列表,然后按字母排序

我有字符串数组列表:

"1A", "12A", "12B", "6", "A", "5B", "B", "13"

如果我做myList.Sort(); 然后我得到:

"1A", "12A", "12B", "13", "5B", "6", "A", "B"

但我需要的是先按照前面的数字排序,然后按字母排序:

"1A", "5B", "6", "12A", "12B", "13", "A", "B"

我可以用

 public class CustomComparer : IComparer { Comparer _comparer = new Comparer(System.Globalization.CultureInfo.CurrentCulture); public int Compare(object x, object y) { // Convert string comparisons to int return _comparer.Compare(Convert.ToInt32(x), Convert.ToInt32(y)); } } 

但它抛出exception。 我如何得到我需要的东西?

您不能简单地将字符串"1A""5B"传递给Convert.ToInt32(x) ,因为它的一部分不是Int32一部分。

相反,您应该首先将字符串拆分为两部分 – 数字和其他所有部分,并使用tie tie进行比较。

一种方法是编写两个辅助方法,然后使用LINQ的OrderByThenBy

 static int ExtractPrefix(string s) { // Parse the digits and stop; return the number } static string ExtractSuffix(string s) { // Skip digits, and return everything else } ... var sorted = unsorted.OrderBy(ExtractPrefix).ThenBy(ExtractSuffix).ToList(); 

你的比较器太简单了。 您的比较需要将每个值拆分为数字和其余值,然后首先比较数字,然后比较字符串是否相等。 所以它会是这样的:

 public sealed class NumberStringComparer : IComparer { public int Compare(string x, string y) { return NumberString.Parse(x).CompareTo(NumberString.Parse(y)); } private struct NumberString : IComparable { private readonly int? number; private readonly string text; private NumberString(int? number, string text) { this.number = number; this.text = text; } internal static NumberString Parse(string text) { // TODO: Find where the digits stop, parse the number // (if there is one), call the constructor and return a value. // (You could use a regular expression to separate the parts...) } public int CompareTo(NumberString other) { // TODO: Compare numbers; if they're equal, compare // strings } } } 

如果你遇到任何一个TODO问题(花了一些时间尝试),你可以要求更具体的帮助 – 但这是我使用的一般方法。

试试这个:

 public class CustomComparer : IComparer { Comparer _comparer = new Comparer(System.Globalization.CultureInfo.CurrentCulture); public int Compare(string x, string y) { string numxs = string.Concat(x.TakeWhile(c => char.IsDigit(c)).ToArray()); string numys = string.Concat(y.TakeWhile(c => char.IsDigit(c)).ToArray()); int xnum; int ynum; if (!int.TryParse(numxs, out xnum) || !int.TryParse(numys, out ynum)) { return _comparer.Compare(x, y); } int compareNums = xnum.CompareTo(ynum); if (compareNums != 0) { return compareNums; } return _comparer.Compare(x, y); } } 

试试这个实现?

http://www.dotnetperls.com/alphanumeric-sorting

从上面的链接:

 public class AlphanumComparatorFast : IComparer { public int Compare(object x, object y) { string s1 = x as string; if (s1 == null) { return 0; } string s2 = y as string; if (s2 == null) { return 0; } int len1 = s1.Length; int len2 = s2.Length; int marker1 = 0; int marker2 = 0; // Walk through two the strings with two markers. while (marker1 < len1 && marker2 < len2) { char ch1 = s1[marker1]; char ch2 = s2[marker2]; // Some buffers we can build up characters in for each chunk. char[] space1 = new char[len1]; int loc1 = 0; char[] space2 = new char[len2]; int loc2 = 0; // Walk through all following characters that are digits or // characters in BOTH strings starting at the appropriate marker. // Collect char arrays. do { space1[loc1++] = ch1; marker1++; if (marker1 < len1) { ch1 = s1[marker1]; } else { break; } } while (char.IsDigit(ch1) == char.IsDigit(space1[0])); do { space2[loc2++] = ch2; marker2++; if (marker2 < len2) { ch2 = s2[marker2]; } else { break; } } while (char.IsDigit(ch2) == char.IsDigit(space2[0])); // If we have collected numbers, compare them numerically. // Otherwise, if we have strings, compare them alphabetically. string str1 = new string(space1); string str2 = new string(space2); int result; if (char.IsDigit(space1[0]) && char.IsDigit(space2[0])) { int thisNumericChunk = int.Parse(str1); int thatNumericChunk = int.Parse(str2); result = thisNumericChunk.CompareTo(thatNumericChunk); } else { result = str1.CompareTo(str2); } if (result != 0) { return result; } } return len1 - len2; } } 

以下比较器的实现应符合您的要求:

 public int Compare(string x, string y) { var rx = new Regex("^(d+)"); var xRes = rx .Match(x); var yRes = rx .Match(y); if (xRes.Success && yRes.Success) { return int.Parse(xRes.Groups[1].Value). CompareTo(int.Parse(yRes.Groups[1].Value)); } return x.CompareTo(y); }