Check the following code:
string toLowerCase(const string& str) {
string res(str);
int i;
for (i = 0; i < (int) res.size(); i++)
res[i] = (char) tolower(res[i]);
return res;
}
class LeagueComparator
{
public:
bool operator()(const string& s1, const string& s2)
{
return toLowerCase(s1) < toLowerCase(s2);
}
};
int main()
{
set<string, LeagueComparator> leagues;
set<string, LeagueComparator>::iterator iter;
leagues.insert("BLeague");
leagues.insert("aLeague"); // leagues = {"aLeague", "BLeague"}
leagues.insert("ALeague");
for (iter = leagues.begin(); iter != leagues.end(); iter++)
cout << *iter << endl;
return 0;
}
The output is:
aLeague
BLeague
which is shocking to me. I thought (and expecting) the output would be:
aLeague
ALeague
BLeague
Before the execution of leagues.insert("ALeague");
, the leagues
contains "aLeague"
and "BLeague"
. My question is, while executing leagues.insert("ALeague");
why the machine treats "ALeague" == "aleague"
? According to my understanding, there is no element "ALeague"
in leagues
. So "ALeague"
should be inserted into leagues
. The comparator should determine where to put "ALeague"
.
Thanks in advance.
PS: Please don't hit me for using C style cast. :P I'm too lazy to type static_cast
.
auto cmp = [](int a, int b) { return ... }; std::set<int, decltype(cmp)> s; We use lambda function as comparator. As usual, comparator should return boolean value, indicating whether the element passed as first argument is considered to go before the second in the specific strict weak ordering it defines.
The comparator class compares the student to be searched from the list of students on the basis of their name attribute. If the name attribute of the object to be searched is equal to any of the object's name attribute in the list then it returns true, otherwise, it returns false.
If you compare age first and then compare name if the ages are equal, the sequence will be sorted by age -- but within each subsequence where the age is equal, that subsequence is sorted by name.
The comparator function takes two arguments and contains logic to decide their relative order in sorted output. The idea is to provide flexibility so that qsort() can be used for any type (including user defined types) and can be used to obtain any desired order (increasing, decreasing or any other).
Your comparator, thanks to the toLowerCase
, says that "aLeague" == "ALeague"
. Since (according to your comparator) "aLeague" < "ALeague" == false
and "ALeague" < "aLeague" == false
, they must be equivalent. And inserting an equivalent element into a set doesn't do anything.
When you insert any value to a set, the object checks to see whether it already contains that value. Your LeagueComparator
object compares ALeague
with the other two values already in the set. It determines that the existing value aLeague
is neither greater than nor less than the proposed new entry (ALeague
), so they must be equal, and so it doesn't proceed with the insert. The set remains with just two elements. That's the whole point of providing a customer comparison object, so you can control how the set determines whether two elements match.
Given the comparator you provided, "ALeague" is indeed equivalent "aLeague".
Given two values, x and y, and a less-than comparator z:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With