开发者

Sorting List of Strings

I'm having a List<String> l_lstTemp and which contains

"A1"
"A1_1"
"A1_2"
"1A"
"B2_1"
"B1_2"
"B1_开发者_运维百科1_2"
"A10"
"B11"
"A"
"Z"

I need to sort the items based on the character and numeric value.

So the sorted list will be like

"1A"
"A"
"A1"
"A1_1"
"A1_2"
"A10"
"B1_1_2"
"B1_2"
"B2_1"
"B11"
"Z"

Here is my code:

l_lstTemp.Sort(delegate(String One, String Two)
{
    Match l_mOne = Regex.Match(One, @"(\D*)(\d*)");
    Match l_mTwo = Regex.Match(Two, @"(\D*)(\d*)");
    int Result;
    if (l_mOne.Success || l_mTwo.Success)
    {
        String l_strX, l_strY;
        l_strX = l_mOne.Groups[1].Value;
        l_strY = l_mTwo.Groups[1].Value;
        Result = l_strX.CompareTo(l_strY);
        if (Result != 0)
            return Result;
        l_strX = l_mOne.Groups[2].Value;
        l_strY = l_mTwo.Groups[2].Value;
        if (l_strX == String.Empty || l_strY == String.Empty)
        {
            Result = l_strX.CompareTo(l_strY);
            if (Result != 0)
                return Result;
        }
        else
        {
            long X = long.Parse(l_strX);
            long Y = long.Parse(l_strY);
            Result = X.CompareTo(Y);
            if (Result != 0)
                return Result;
        }

    }
    return 0 ;
}
);

But its not working (sorting) properly.

How do I modify my code to sort the list properly?

Please post me a way to do this.

Thanks in advance.


I did some modifications to your code. The thing was that when both Group 1 and Group 2 are equals, you still need to check what remains.

Important: I did the modifications inside your code, so this could be a little tricky. I really suggest you refactoring your code now that you know it works:

l.Sort(delegate(String One, String Two)
{
    while (One != "" && Two != "")
    {
        if (One == Two)
            return 0;

        //Add one more group to capture what remains of the expression
        Match l_mOne = Regex.Match(One, @"_*(\D*)(\d*)(.*)$"); 
        Match l_mTwo = Regex.Match(Two, @"_*(\D*)(\d*)(.*)$");
        int Result;
        if (l_mOne.Success || l_mTwo.Success)
        {
            String l_strX, l_strY;
            l_strX = l_mOne.Groups[1].Value;
            l_strY = l_mTwo.Groups[1].Value;
            Result = l_strX.CompareTo(l_strY);
            if (Result != 0)
                return Result;
            l_strX = l_mOne.Groups[2].Value;
            l_strY = l_mTwo.Groups[2].Value;
            if (l_strX == String.Empty || l_strY == String.Empty)
            {
                Result = l_strX.CompareTo(l_strY);
                if (Result != 0)
                    return Result;
            }
            else
            {
                long X = long.Parse(l_strX);
                long Y = long.Parse(l_strY);
                Result = X.CompareTo(Y);
                if (Result != 0)
                    return Result;
                One = l_mOne.Groups[3].Value; //Store in 'One' the remaining part of the regex
                Two = l_mTwo.Groups[3].Value; //The same in Two

                continue; //The result will be the result of the comparison of those two new values.
            }

        }
    }
    return One.CompareTo(Two);
});

Edit:
I also added _* to remove all the _ characters from the begining of the strings. I assumed here that the strings will only contain _ after the numbers and not something like B1B or B1$.

The thing here is that you don't really explain how the comparison should be made, and I had to assume those things from your original data and the sorted data, otherwise what would happen if you want to sort A1A and A1_? What should it return?


Here's how I would implement such a comparer. Much easier to follow IMHO.

var re = new Regex(@"^(\d+)?([A-Z]+)(\d+)?(?:_(\d+)(?:_(\d+))?)?$");
Func<Group, int, int> intOrDefault = (g, d) => g.Success ? Convert.ToInt32(g.Value) : d;
list.Sort((x, y) =>
{
    var xm = re.Match(x);
    var ym = re.Match(y);
    int cmp;

    // compare the first group
    // compare the leading numbers (if any)
    cmp = intOrDefault(xm.Groups[1], int.MaxValue).CompareTo(intOrDefault(ym.Groups[1], int.MaxValue));
    if (cmp != 0)
        return cmp;
    // compare letters
    cmp = xm.Groups[2].Value.CompareTo(ym.Groups[2].Value);
    if (cmp != 0)
        return cmp;
    // compare the trailing numbers (if any)
    cmp = intOrDefault(xm.Groups[3], 0).CompareTo(intOrDefault(ym.Groups[3], 0));
    if (cmp != 0)
        return cmp;

    // compare the next group
    cmp = intOrDefault(xm.Groups[4], 0).CompareTo(intOrDefault(ym.Groups[4], 0));
    if (cmp != 0)
        return cmp;

    // compare the last group
    cmp = intOrDefault(xm.Groups[5], 0).CompareTo(intOrDefault(ym.Groups[5], 0));
    return cmp;
});


For this example, just calling sort l_lstTemp.Sort() would get you the result you are looking for

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜