0

I am trying to reorder the map in a descending way depending on the values, I have been trying to create a new map and insert the one which has the biggest value first but it keeps ordering the map by the keys.

I have also tried to reorder it by the value changing the form of the map into the other way but I will loose some data because I have more than one key which has the same value.

#include <iostream>
#include "SymbolFreq.h"
#include <string>
#include <fstream>
#include <streambuf>
#include <map>

using namespace std;

int main()
{
    map <char, int> mymap;
    map <char, int> realmap;

    ifstream infile{ "ToCompress.txt" };
    std::string str((std::istreambuf_iterator<char>(infile)),
        std::istreambuf_iterator<char>());
    


    std::map<char, int>::iterator itera;






    for (auto it = str.begin(); it != str.end(); ++it)
    {
        itera = mymap.find(*it);

        if (itera != mymap.end())
        {
            itera->second++;
        }
        else
        {
            mymap.insert({ *it, 1 });
        }


    }

    int max = 0;
    char provisionalChar;
    int provisionalInt;

    while (mymap.empty() == false)
    {
        for (auto it = mymap.cbegin(); it != mymap.cend(); ++it)
        {
            if (it->second > max)
            {
                max = it->second;
                provisionalChar = it->first;
                provisionalInt = it->second;
            }
            
            
            //cout << it->first << "\t" << it->second << "\n";
        }
        mymap.erase(provisionalChar);
        realmap.insert({ provisionalChar, provisionalInt });
        max = 0;
    }

    for (auto it = realmap.cbegin(); it != realmap.cend(); ++it)
    {
    
        cout << it->first << "\t" << it->second << "\n";
    }




    return 0;
}
JustCode
  • 463
  • 2
  • 11
  • Maybe try `std::unordered_map`? – Thomas Matthews Apr 26 '21 at 17:24
  • 2
    you cannot change the ordering of elements in a `std::map`, only by supplying the map with a different comparator the map can keep them in different order – 463035818_is_not_an_ai Apr 26 '21 at 17:27
  • 1
    When posting code to StackOverflow you should eliminate the extra / somewhat random line feeds in the code to make scrolling less necissary. – drescherjm Apr 26 '21 at 17:30
  • 3
    If you want to change the order of the elements you can't use `std::map`, `std::multimap`, `std::set`, or `std::multiset`. They manage the order of elements themselves. Instead, use a container that doesn't insist on things being in order. `std::vector` is the most obvious choice. – Pete Becker Apr 26 '21 at 17:31
  • *I am trying to reorder the map* -- Cannot be done. The order is set in stone once the `std::map` is declared. – PaulMcKenzie Apr 26 '21 at 17:36
  • You may want to look into boost.multiindex – Slava Apr 26 '21 at 17:37
  • Unordered_map is the one you are looking for or unordered_multimap if you are looking for repetitive keys – saumitra mallick Apr 26 '21 at 18:00

2 Answers2

1

If I understand the question properly, you'd like to count how many times each char appears in the file and then produce a map sorted with the char that appeared most time first.

Here's one idea:

#include <algorithm>
#include <cstdint>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <map>
#include <string>
#include <unordered_map>

int main() {
    std::ifstream infile{"ToCompress.txt"};

    // "mymap" is only used for counting how many times each char appears.
    std::unordered_map<char, std::uintmax_t> mymap;

    // Loop directly over the file. No vector needed:
    std::for_each(std::istreambuf_iterator<char>(infile),
                  std::istreambuf_iterator<char>(), [&mymap](char ch) {
                      // No need to find first - operator[] inserts an element
                      // for the key ("ch") if it's missing.
                      ++mymap[ch];
                  });

    // Transform the unordered_map into a multimap where the count is the key
    // and in which we use a descending sort order (std::greater):
    std::multimap<std::uintmax_t, char, std::greater<std::uintmax_t>> realmap;

    std::transform(mymap.begin(), mymap.end(),
                   std::inserter(realmap, realmap.end()),
                   [](const auto& ch_co) -> std::pair<std::uintmax_t, char> {
                       // return a pair with key and value swapped
                       return {ch_co.second, ch_co.first};
                   });

    // Print the result
    for(auto& [count, ch] : realmap) {
        std::cout << count << '\t' << ch << '\n';
    }
}

Possible output:

537479
120204  t
113285  e
80681

80670   i
79862   n
77984   r
77464   s
69994   o
67377   a
...

Apparently, <space>, t, e and \n are tne most common characters in my C++ programs (which is what I used as input)

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
0

Your question may be ill-posed; take a step back and state what you are really trying to accomplish.

That said, I'll attempt an answer based on what you've written.

It looks like you're trying to sort an std::map by value, in which case your question is a duplicate of either this or this question.

Regarding your initial attempt:

Take a look at this table. Only sequence containers allow you to directly influence order. As with priority queue you have limited control over the order of associative containers and almost zero control for unordered containers.

Brian Vandenberg
  • 4,011
  • 2
  • 37
  • 53