2

My company has a rating system for it's users (string format right now). The system is a typical, A+, A, A-, B+, B...F

I would like to be able to compare them so that I can build rules like: if UserJoe.Rating > Ratings.B give him special offer.

I am a bit new to the IComparer idea, what is the recommended approach to building this?

Thanks for any input

FailedUnitTest
  • 1,637
  • 3
  • 20
  • 43
  • 1
    *Don't* use a string format, or parse/map the string into a number. Create a dictionary that maps the ratings to numbers and use the numbers for comparisons. – Panagiotis Kanavos Feb 16 '17 at 15:28
  • Probably worth using the 4.0 scale, then just compare that # when implementing the > and < operators. – Peter Ritchie Feb 16 '17 at 15:30
  • Start with making `class Rating` and `ToString()`. Then just add [IComparer](http://stackoverflow.com/q/14336416/1997232). You can internally present various ratings as members of `enum`, that would make them easily comparable. – Sinatr Feb 16 '17 at 15:31

4 Answers4

3

How about an enum? They are natively comparable.

public enum Rating
{
    F  = 0,
    [Description("D-")]
    Dm = 1,
    D  = 2,
    [Description("D+")]
    Dp = 3,
    [Description("C+")]
    Cm = 4,
...
}

You can also add attributes to use "D+" and "C-" as the display names.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • Explaining the throwaway comment about the attributes would be a good idea in my opinion. – TheLethalCoder Feb 16 '17 at 15:40
  • And I guess, I could have a dictionary to convert from my existing strings? – FailedUnitTest Feb 16 '17 at 15:40
  • @FailedUnitTest - Just use Enum.Parse or Enum.TryParse for that. `Enum.Parse(typeof(Rating), stringRatingVal)` – Dusty Feb 16 '17 at 15:49
  • @FailedUnitTest It depends on what you expect to parse. `"D+"` is not a valid identifier, so you would need to convert `-` to `m` or use a dictionary to cress-reference. – D Stanley Feb 16 '17 at 16:14
1

My understanding is that you are using strings at the minute so to keep it compatible with what you've got you can do this. Lookup time is O(1) because of the Dictionary so it's always going to perform well, only thing you need to tweak is the numbers (I'd personally start quite high so you don't need to rewrite all the values when you add a new one.)

Dictionary<string, int> Ratings = new Dictionary<string, int>() {
    { "A+", 6 },
    { "A", 5 },
    { "A-", 4 },
    { "B+", 3 },
    { "B", 2 }
};

Then just access the rating like Ratings[UserJoe.Rating] > Ratings["B"] and you can compare them directly

Edit: You can of course take this further and have a class RatingComparator which has this stored as a private static Dictionary<string, int> and exposes a function which compares two Rating strings for you (int CompareRatings(string rating1, string rating2)).

Daniel Wardin
  • 1,840
  • 26
  • 48
0

Enums works just fine:

public enum Ratings
{
  Fm,  // F-
  F,   // F
  Fp,  // F+
  Em,  // E-
  E,   // E
  Ep,  // E+
  Dm,  // D-
  D,   // D
  Dp,  // D+
  Cm,  // C-
  C,   // C
  Cp,  // C+
  Bm,  // B-
  B,   // B
  Bp,  // B+
  Am,  // A-
  A,   // A
  Ap   // A+
}

public class User
{
  public string Name { get; set; }
  public Ratings Rating { get; set; }
  public User(string name, Ratings rating)
  {
    Name = name;
    Rating = rating;
  }
}

...

var user1 = new User("Joe", Ratings.Bp);
var user2 = new User("Alex", Ratings.D);

if (user1.Rating > user2.Rating)
  ...
Sani Huttunen
  • 23,620
  • 6
  • 72
  • 79
0

If you have string representations of rates to compare, you can use a trick: since

   '+' == 0x2B
   ',' == 0x2C
   '-' == 0x2D

we can compare left and right ratings by padding them with ',': "X+" < "X," < "X-"

   int compare = string.Compare(
     left.PadRight(2, ','), 
     right.PadRight(2, ','), 
     StringComparison.OrdinalIgnoreCase);

For instance, let's sort out an array of ratings given as strings:

   string[] ratings = new string[] {
     "F-", "A+", "B", "B-", "B+", "A-", "F", "E"
   };

   // Inplace sorting
   Array.Sort(ratings, (left, right) => string.Compare(
     left.PadRight(2, ','), 
     right.PadRight(2, ','), 
     StringComparison.OrdinalIgnoreCase));

   // Alternative Linq version
   var sortedRatings = ratings
     .OrderBy(rating => rating.PadRight(2, ','))
     .ToArray();

   Console.Write(string.Join(", ", ratings));

Outcome:

   A+, A-, B+, B, B-, E, F, F-
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215