Rocko'Steele
Rocko'Steele

Reputation: 69

How to sort values in a map in C++

I am trying to sort my output based on the value and I am unsure on how to approach it. This is my current output:

 E:2  
 H:1 
 I:3 
 L:2 
 N:3 
 O:2 
 S:2
 T:1 
 Y:1 

This is how I want my output:

 I: 3 
 N: 3
 E: 2 
 L: 2 
 O: 2 
 S: 2 
 H: 1 
 T: 1 
 Y: 1

My code:

#include<iostream>
using std::cin;
using std::cout;
using std::endl;
#include<string>
using std::string;
#include<map>
using std::map;
#include<algorithm>
using std::sort;

int main()
{
    string input;
    int line = 0;
    map<char, int> letters;
    while (getline(cin, input))
    {
        line += 1;
        for (int i = 0; i < input.length(); i++)
        {
            if (isalpha(input[i]))
            {
                if (letters.count(toupper(input[i])) == 0)
                {
                    letters[toupper(input[i])] = 1;
                }
                else
                {
                    letters[toupper(input[i])] += 1;
                }
            }
        }
    }

    cout << "Processed " << line << " line(s)." << endl;
    cout << "Letters and their frequency:" << endl;
    for (auto it = letters.cbegin(); it != letters.cend(); ++it)
    {

        cout << it->first << ":" << it->second << "\n";

    }
}

Upvotes: 3

Views: 3576

Answers (1)

Vlad from Moscow
Vlad from Moscow

Reputation: 311146

We beginners should help each other.:)

In any case you need a second container because the std::map is already sorted by key.

A general approach is to copy the map in some other container and sort the new container before outputting it.

For your task you can use std::set as the second container.

Here you are.

#include <iostream>
#include <map>
#include <set>
#include <utility>

int main()
{
    std::map<char, size_t> m =
    {
        { 'E', 2 }, { 'H', 1 }, { 'I', 3 }, { 'L', 2 },
        { 'N', 3 }, { 'O', 2 }, { 'S', 2 }, { 'T', 1 },
        { 'Y', 1 }
    };

    for (const auto &p : m)
    {
        std::cout << "{ " << p.first << ", " << p.second << " }\n";
    }
    std::cout << std::endl;

    auto cmp = [](const auto &p1, const auto &p2)
    {
        return p2.second < p1.second || !(p1.second < p2.second) && p1.first < p2.first;
    };

    std::set < std::pair<char, size_t>, decltype( cmp )> s(m.begin(), m.end(), cmp);

    for (const auto &p : s)
    {
        std::cout << "{ " << p.first << ", " << p.second << " }\n";
    }
    std::cout << std::endl;
}

The program output is

{ E, 2 }
{ H, 1 }
{ I, 3 }
{ L, 2 }
{ N, 3 }
{ O, 2 }
{ S, 2 }
{ T, 1 }
{ Y, 1 }

{ I, 3 }
{ N, 3 }
{ E, 2 }
{ L, 2 }
{ O, 2 }
{ S, 2 }
{ H, 1 }
{ T, 1 }
{ Y, 1 }

Also pay attention to that in your program instead of this if-else statement

if (letters.count(toupper(input[i])) == 0)
{
    letters[toupper(input[i])] = 1;
}
else
{
    letters[toupper(input[i])] += 1;
}

you can just write

++letters[toupper(input[i])];

Upvotes: 3

Related Questions