Search code examples
c++sortingc++11dictionaryalphabetical

C++ Printing a map in a case-insensitive, alphabetical order


I have a:

map<string, map<int,int>>

Is there a way to print the contents of this map in alphabetical order, but case insensitive? For example, have it print in the following order:

A : 1:1, 2:2
a : 3:1
an : 2:1
And : 4:1
and : 3:1

Currently, I am printing using the following:

for (auto it = tokens.begin(); it != tokens.end(); ++it){
    cout << it->first << " : ";
    auto const &internal_map = it->second;
    for (auto it2 = internal_map.begin(); it2 != internal_map.end(); ++it2){
        if (it2 != internal_map.begin())
            cout << " , ";
        cout << it2->first << ":" << it2->second;
    }       
    cout << endl;
}

This prints everything, however, it goes through all uppercase first, followed by all lowercase. For example:

A : 1:1, 2:2
And : 4:1
a : 3:1
an : 2:1
and : 3:1

Solution

  • Is there a way to print the contents of this map in alphabetical order, but case insensitive?

    Yes.

    1. You will have to create a custom compare functor that compares two strings in a case insensitive manner.

      struct cicompare
      {
         bool operator()(std::string const& lhsIn, std::string const& rhsIn) const
         {
           char const* lhs = lhsIn.c_str();
           char const* rhs = rhsIn.c_str();
           for ( ; *lhs != '\0' && *rhs != '\0'; ++lhs, ++rhs )
           {
              if ( tolower(*lhs) != tolower(*rhs) )
              {
                 return ( tolower(*lhs) < tolower(*rhs) );
              }
              else if ( *lhs != *rhs)
              {
                 if ( *(lhs+1) == '\0' && *(rhs+1) == '\0' )
                 {
                    return (*lhs < *rhs);
                 }
              }
           }
           return (tolower(*lhs) < tolower(*rhs));
         }
      };
      
    2. Use the case insensitive compare functor to create the map.

      map<string, map<int,int>, cicompare> mymap;
      
    3. If you don't want to store your map ordered in a case insensitive manner, create a copy of the original map using cicompare just before printing and print the new map.

      map<string, map<int,int>, cicompare> mapForPrinting;
      mapForPrinting.insert(originalMap.start(), originalMap.end());