Ok, this is a range to value issue, and in this case you have very few ranges, but I still would prefer to see the use of a "map". Assuming percentage is an int, you could do something like this:
std::map< int, char > gradeMap;
// initialisation code, but can be read from config etc.
// Stored somewhere.
gradeMap[ 90 ] = 'A';
gradeMap[ 80 ] = 'B';
gradeMap[ 70 ] = 'C';
gradeMap[ 60 ] = 'D';
gradeMap[ 0 ] = 'F';
to look up my grade from a percentage, you can use upper_bound
auto iter = gradeMap.upper_bound( grade );
This will actually get me the iterator one higher than the one I want. Thus if it is "begin" I have a grade 'Z' otherwise I should subtract one from the iterator.
if( iter == gradeMap.begin() )
{
return 'Z';
}
else
{
--iter;
return iter->second;
}
However this is rather annoying. So there are 2 ways we can fix it. Either change the predicate in the map to sort downward. Or simply make our keys negative. We are hiding the implementation so it doesn't matter.
gradeMap[ -90 ] = 'A';
gradeMap[ -80 ] = 'B';
gradeMap[ -70 ] = 'C';
gradeMap[ -60 ] = 'D';
gradeMap[ 0 ] = 'F';
Now we can use lower_bound
on -grade
. Note it changes from upper_bound before to lower_bound because of the case where our value is equal to the value.
The difference between lower_bound
and upper_bound
is when the searched value equals the key, and this time we want the cell we are in, not the cell below it, so we want lower_bound
.
If our percentage is, say 75 we would now search for -75 which falls between -80 and -70 but the lower bound is the one that has -70 because lower_bound
returns the first cell whose value is greater than or equal to the searched value. (upper_bound
returns the first cell whose value is strictly greater. It would work for -75 but not for -70 itself).
char get_grade( int percent )
{
auto iter = gradeMap.lower_bound( -percent );
if( iter == gradeMap.end() )
return 'Z';
else
return iter->second;
}
It's not really the place here to teach the user the full detail of what std::map
is. I will summarise to say firstly that it is one of the main collection classes in the standard library, and is mostly used as an associative array, that is, a unique key on which you look up and find its associated value. Used that way, the key either exists or it doesn't.
However there are occasions where you are not interested in exact key values but ranges, and you can take advantage of the fact that map
is a sorted container on its keys and that you can use lower_range
and upper_range
to find the points where your "key" belongs even if it is not actually in the container. (The only difference between lower_bound and upper_bound is when the key does exist). The fact that it returns an iterator, which can either point to one of the elements or one past the last one.
And that it is logarithmic in its lookup. For this instance where you have just 5 keys the performance doesn't really matter, but it's useful to know in general as part of your general education.
That you can use it to solve this particular kind of problem in C++ is useful. Some languages only use hash-table lookup for associative containers, which can be faster when it is only an exist/not exist situation but not useful for ranges at all.