15

I am new to stl's. Here is my below program.

typedef pair<string, int> p;
int main(int argc, char *argv[])
{
  map<string,int> st;
  st.insert(p("hello",1));   //Inserted "hello" as key to map.
  st.insert(p("HELLO",1));   //Inserted "HELLO" as key to map. 
  cout<<"size="<<st.size()<<endl;    //Output is 2 because two records found "hello" and "HELLO"
  return 0;
}

I don't want to take account of the repeated case changes(upper case to lower case words or vice-versa). Here "st.insert(p("HELLO",1));" should fail, hence the no. of records should be "1" instead of "2". Is there any flag setup or like so?

I was unable to find the related questions hence posted this question.

Any help is thankful.

Santosh Sahu
  • 2,134
  • 6
  • 27
  • 51

2 Answers2

35

Use a custom comparator:

struct comp { 
    bool operator() (const std::string& lhs, const std::string& rhs) const {
        return stricmp(lhs.c_str(), rhs.c_str()) < 0;
    }
};

std::map<std::string, int, comp> st;

Edit : If you're not able to use stricmp or strcasecmp use :

#include<algorithm>
//...
string tolower(string s) {
    std::transform(s.begin(), s.end(), s.begin(), ::tolower );
    return s;
}
struct comp { 
    bool operator() (const std::string& lhs, const std::string& rhs) const {
        return  tolower(lhs) < tolower(rhs);
    }
};

std::map<std::string, int, comp> st;
P0W
  • 46,614
  • 9
  • 72
  • 119
  • 7
    I wouldn't recommend the second option (with the `tolower` function) as it creates a new string. Which means a couple of `new` and `delete`s per comparison operator. Which will GREATLY slow you down. Also it turns the comparison from `O(1)` on average (most strings differ in the first character) to `O(s)` where s is the average size of the string. So instead of a single character comparison you get 2 `new`, 2 `delete`, 2xs `tolower`... no. – rabensky Sep 30 '13 at 19:58
  • Can you explain why the return is < 0 and not == 0? I thought with str***cmp functions, less than zero indicates that left hand side is a substring of right hand, where an equal match is 0. –  Nov 08 '15 at 15:13
  • 2
    @TechnikEmpire The map is based on a "less than" comparison: The default comparator is the `std::less` predicate. The same behaviour is achieved here by checking if `stricmp(lhs, rhs)` is less than 0. – Felix Dombek Apr 14 '16 at 16:02
2

There are two ways to do this

First - change the "comparison" function to ignore case

Second - whenever you use a string to either put or get a value from the map, wrap it with a function that turns it into lowercase.

For the first all you need to do is create a "function class" (a class with operator() ) that receives two strings and returns whether the left is "smaller" than the right:

struct my_comparitor{
  bool operator()(const std::string &a, const std::string &b){
    // return iwhether a<b
  }
};

std::map<std::string,DATA_TYPE,my_comparitor> my_map;

For the second just do this:

std::map<std::string,DATA_TYPE> my_map;
my_map.insert(std::make_pair(TO_LOWERCASE("hello"),1));
iter=my_map.find(TO_LOWERCASE(key));
cout << my_map[TO_LOWERCASE(name)];
// etc.

I'm not sure if a function that transforms to lowercase is already part of stl - but either way it's easy to write.

rabensky
  • 2,864
  • 13
  • 18