简体   繁体   中英

Custom string Comparison in C#

I want to implement a custom string IComparer in C# and apply it to a ComboBox.

Actual Results

If I set the ComboBox 's Sorted property to true , the output is :

A
AA
AAA
B
BB
BBB

Wanted Results

The wanted behavior of the sorting algorithm is the following (financial developers will understand why :) ) :

AAA
AA
A
BBB
BB
B

Question

Is it possible to do it ? Are sorting algorithms needed here ?

PS : I don't need a complete answer with code, i just need an idea of how it might be done ..

EDIT

This is about credit ratings. I've omitted something in my question. The ratings have to be sorted in this order :

XXX
XX+
XX
XX-
X+
X
X-

with X in ('A','B','C') and 'A' > 'B' > 'C'

Here's a mostly implemented version:

public class MyComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        //todo null checks on input

        var pairs = x.Zip(y, (a, b) => new { x = a, y = b });

        foreach (var pair in pairs)
        {
            int value = pair.x.CompareTo(pair.y);
            if (value != 0)
                return value;
        }


        //if we got here then either they are the same,
        //or one starts with the other
        return y.Length.CompareTo(x.Length); //note x and y are reversed here
    }
}

So this uses Zip to get the pairs of chars from each corresponding string until one ends, returning the appropriate value if they aren't equal. If it makes it past that then one string start with the other. For a traditional string comparison we'd just compare the lengths in the same order as the input parameters. Since we're essentially reversing the order based on length, note that the x and y are swapped on the last line. That reverses the comparison logic.

Assuming this is for credit ratings, normally this is done by having a "sort order" column on the CreditRating class that you could use to sort the list before assigning it as the data source of the drop-down.

But, a quick workaround (based on the limited possible values) would be to sort by the first letter ascending, then by the length of the string descending:

if(left[0] != right[0])
    return left[0].CompareTo(right[0]);
else
    return right.Length - left.Length;

Another workaround if you want more control over the order is to create a list of possible values in the "right" order and then use that to sort the list:

public class MyComparer : IComparer<string>
{
    private static readonly string[] Ratings = new [] {
        "CC","C","CCC-","CCC","CCC+",
        "B-","B","B+","BB-","BB","BB+","BBB-","BBB","BBB+",
        "A-","A","A+","AA-","AA","AA+","AAA"};
    // reverse the order so that any strings not found will be put at the end.

    public int Compare(string left, string right)
    {
       return Array.IndexOf(Ratings, right).CompareTo(Array.IndexOf(Ratings, left));
    }
}

Write the IComparer so that it takes strings but compares per character,

if A[0] == B[0] go to the next character.
if B[1] == null or A[1] < B[1], return A < B.
if A[1] == null or B[1] < A[1], return B < A.
if equal...continue as needed

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM