How can I use C# to sort values numerically?

前端 未结 9 1486
醉话见心
醉话见心 2021-02-20 03:20

I have a string that contains numbers separated by periods. When I sort it appears like this since it is a string: (ascii char order)

3.9.5.2.1.1
3.9.5.2.1.10
3.         


        
9条回答
  •  醉酒成梦
    2021-02-20 03:40

    Here's my working solution that also takes care of strings that are not in the right format (e.g. contain text).

    The idea is to get the first number within both strings and compare these numbers. If they match, continue with the next number. If they don't, we have a winner. If one if these numbers isn't a number at all, do a string comparison of the part, which wasn't already compared.

    It would be easy to make the comparer fully compatible to natural sort order by changing the way to determine the next number.

    Look at that.. just found this question.

    The Comparer:

    class StringNumberComparer : IComparer
    {
        public int Compare(string x, string y)
        {
            int compareResult;
            int xIndex = 0, yIndex = 0;
            int xIndexLast = 0, yIndexLast = 0;
            int xNumber, yNumber;
            int xLength = x.Length;
            int yLength = y.Length;
    
            do
            {
                bool xHasNextNumber = TryGetNextNumber(x, ref xIndex, out xNumber);
                bool yHasNextNumber = TryGetNextNumber(y, ref yIndex, out yNumber);
    
                if (!(xHasNextNumber && yHasNextNumber))
                {
                    // At least one the strings has either no more number or contains non-numeric chars
                    // In this case do a string comparison of that last part
                    return x.Substring(xIndexLast).CompareTo(y.Substring(yIndexLast));
                }
    
                xIndexLast = xIndex;
                yIndexLast = yIndex;
    
                compareResult = xNumber.CompareTo(yNumber);
            }
            while (compareResult == 0
                && xIndex < xLength
                && yIndex < yLength);
    
            return compareResult;
        }
    
        private bool TryGetNextNumber(string text, ref int startIndex, out int number)
        {
            number = 0;
    
            int pos = text.IndexOf('.', startIndex);
            if (pos < 0) pos = text.Length;
    
            if (!int.TryParse(text.Substring(startIndex, pos - startIndex), out number))
                return false;
    
            startIndex = pos + 1;
    
            return true;
        }
    }
    

    Usage:

    public static void Main()
    {
        var comparer = new StringNumberComparer();
    
        List testStrings = new List{
            "3.9.5.2.1.1",
            "3.9.5.2.1.10",
            "3.9.5.2.1.11",
            "3.9.test2",
            "3.9.test",
            "3.9.5.2.1.12",
            "3.9.5.2.1.2",
            "blabla",
            "....",
            "3.9.5.2.1.3",
            "3.9.5.2.1.4"};
    
        testStrings.Sort(comparer);
    
        DumpArray(testStrings);
    
        Console.Read();
    }
    
    private static void DumpArray(List values)
    {
        foreach (string value in values)
        {
            Console.WriteLine(value);
        }
    }
    

    Output:

    ....
    3.9.5.2.1.1
    3.9.5.2.1.2
    3.9.5.2.1.3
    3.9.5.2.1.4
    3.9.5.2.1.10
    3.9.5.2.1.11
    3.9.5.2.1.12
    3.9.test
    3.9.test2
    blabla
    

提交回复
热议问题