Search code examples
c++dictionarystlcomparator

Can I reorder elements in map by value? C++


I want to make a table of letter frequency, just like this

So, I have variable str that contains some text, and I have map<char, int> m, that contains number of occurrences of each letter.

So I have something like that:

vector<char> get_rank(const string& str)
{
    map<char, int> m;

    for (char i = 'a'; i <= 'z'; i++)
        m[i] = 0;

    for (char ch : str)
        m[ch]++;

    for (auto& it : m)
        v.push_back(it.first);
    return v;
}

But map is ordered by keys, not by values. Is there a way to "overload" the comparator of map to order each element by value? If the answer is no, how can I implement the same idea but with the same elegancy. Because every idea I have seems a little dull and rough.


Solution

  • It is not possible to sort a map with respect to its mapped values. The order of elements of a map is managed by the map according to its comparator which only considers keys.

    However, you do not need a map to count frequencies when the keys are contiguous and of limited range.

    Instead of a map, use a std::vector<letter_and_count> with

    struct letter_and_count {
         char letter;
         int count = 0;
    };
    

    Initialize the vector with elements with letter initialized to a till z then increment v[ i - 'a'] when you encounter the letter i in the string. Then use std::sort to sort the vector according to the count member.

    PS: Note comments below. The letters a till z are not necessarily contiguous. However (idea also from eerorika) you can use a simple lookup table:

    std::string alphabet{"abcdefghijklmnopqrstuvwxyz"};
    

    Then first find the letter in that alphabet and use its index in the alphabet for the counting.