Array.Sort用于带数字的字符串

时间:2014-04-01 20:44:28

标签: c#

我的示例代码如下:

List<string> test = new List<string>();
test.Add("Hello2");
test.Add("Hello1");
test.Add("Welcome2");
test.Add("World");
test.Add("Hello11");
test.Add("Hello10");
test.Add("Welcome0");
test.Add("World3");
test.Add("Hello100");
test.Add("Hello20");
test.Add("Hello3");

test.Sort();

但是会发生什么,test.Sort会将数组排序为:

"Hello1", 
"Hello10", 
"Hello100", 
"Hello11", 
"Hello2", 
"Hello20", 
"Hello3", 
"Welcome0", 
"Welcome2", 
"World", 
"World3"

有没有办法对它们进行排序,以便string也具有正确的数字顺序?  (如果string末尾没有数字,则string将始终排在第一位 - 按字母顺序排列)

预期产出:

"Hello1", 
"Hello2", 
"Hello3", 
"Hello10", 
"Hello11", 
"Hello20", 
"Hello100", 
"Welcome0", 
"Welcome2", 
"World", 
"World3"

3 个答案:

答案 0 :(得分:7)

以下是使用LINQ的一种可能方式:

 var orderedList = test
            .OrderBy(x => new string(x.Where(char.IsLetter).ToArray()))
            .ThenBy(x =>
            {
                int number;
                if (int.TryParse(new string(x.Where(char.IsDigit).ToArray()), out number))
                    return number;
                return -1;
            }).ToList();

答案 1 :(得分:1)

创建IComparer<string>实施。这种方式优于LINQ建议的优点是你现在有一个类可以传递给需要以这种方式排序的任何东西,而不是在其他位置重新创建linq查询。

这特定于您从LIST呼叫排序。如果您想将其称为Array.Sort(),请参阅第二版:

列表版本:

public class AlphaNumericComparer : IComparer<string>
    {
        public int Compare(string lhs, string rhs)
        {
            if (lhs == null)
            {
                return 0;
            }

            if (rhs == null)
            {
                return 0;
            }

            var s1Length = lhs.Length;
            var s2Length = rhs.Length;
            var s1Marker = 0;
            var s2Marker = 0;

            // Walk through two the strings with two markers.
            while (s1Marker < s1Length && s2Marker < s2Length)
            { 
                var ch1 = lhs[s1Marker];
                var ch2 = rhs[s2Marker];

                var s1Buffer = new char[s1Length];
                var loc1 = 0;
                var s2Buffer = new char[s2Length];
                var loc2 = 0;

                // Walk through all following characters that are digits or
                // characters in BOTH strings starting at the appropriate marker.
                // Collect char arrays.
                do
                {
                    s1Buffer[loc1++] = ch1;
                    s1Marker++;

                    if (s1Marker < s1Length)
                    {
                        ch1 = lhs[s1Marker];
                    }
                    else
                    {
                        break;
                    }
                } while (char.IsDigit(ch1) == char.IsDigit(s1Buffer[0]));

                do
                {
                    s2Buffer[loc2++] = ch2;
                    s2Marker++;

                    if (s2Marker < s2Length)
                    {
                        ch2 = rhs[s2Marker];
                    }
                    else
                    {
                        break;
                    }
                } while (char.IsDigit(ch2) == char.IsDigit(s2Buffer[0]));

                // If we have collected numbers, compare them numerically.
                // Otherwise, if we have strings, compare them alphabetically.
                string str1 = new string(s1Buffer);
                string str2 = new string(s2Buffer);

                int result;

                if (char.IsDigit(s1Buffer[0]) && char.IsDigit(s2Buffer[0]))
                {
                    var thisNumericChunk = int.Parse(str1);
                    var thatNumericChunk = int.Parse(str2);
                    result = thisNumericChunk.CompareTo(thatNumericChunk);
                }
                else
                {
                    result = str1.CompareTo(str2);
                }

                if (result != 0)
                {
                    return result;
                }
            }
            return s1Length - s2Length;
        }
    }
像这样打电话:

test.sort(new AlphaNumericComparer());

//RESULT
Hello1 
Hello2 
Hello3 
Hello10 
Hello11 
Hello20 
Hello100 
Welcome0 
Welcome2 
World 
World3 

Array.sort版本:

创建课程:

public class AlphaNumericComparer : 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)
        {
            var ch1 = s1[marker1];
            var ch2 = s2[marker2];

            // Some buffers we can build up characters in for each chunk.
            var space1 = new char[len1];
            var loc1 = 0;
            var space2 = new char[len2];
            var 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.
            var str1 = new string(space1);
            var str2 = new string(space2);

            var result = 0;

            if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
            {
                var thisNumericChunk = int.Parse(str1);
                var thatNumericChunk = int.Parse(str2);
                result = thisNumericChunk.CompareTo(thatNumericChunk);
            }
            else
            {
                result = str1.CompareTo(str2);
            }

            if (result != 0)
            {
                return result;
            }
        }
        return len1 - len2;
    }
}

Call like so:

This time test is an array instead of a list.
Array.sort(test, new AlphaNumericComparer())

答案 2 :(得分:0)

您可以将LINQ与regex结合使用,以确保仅使用字符串末尾出现的数字进行二次排序

test
  .Select(t => new{match = Regex.Match(t, @"\d+$"), val = t})
  .Select(x => new{sortVal = x.match.Success
                                ?int.Parse(x.match.Value)
                                :-1,
                   val = x.val})
  .OrderBy(x => x.val)
  .ThenBy(x => x.sortVal)
  .Select(x => x.val)
  .ToList()