1

I am using STL map in C++ for counting the frequency of words in a text file and words must be sort in lexicographic order. Input data is given as a text file. Ive already read and added them in map but i got a problem with sorting.

Example, i have { "Abc", "abc", "bag", "Boom", "great"}. When i added them in map, i got

Abc 1 Boom 1 abc 1 bag 1 great 1

but expected result is

Abc 1 abc 1 Boom 1 bag 1 great 1

#include <iostream>
#include <cstring>
#include <map>
#include <fstream>
using namespace std;
typedef map<string, int> word_count;

int main(){
    word_count wc;
    fstream f_in;
    f_in.open("test.in");
    string x;

    while( !f_in.eof()){
        f_in >> x;
        wc[x]++;
    }
    f_in.close();   
    return 0;
}

Here is my code for reading input. Any help for my problem? Thanks

BlackW
  • 31
  • 3
  • Welcome to Stackoverflow. What exactly is your problem with sorting? What have you tried so far. As a general rule, more specific questions here will attract better quality responses. – Matt Nov 11 '18 at 00:07
  • 3
    Notice: https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong – πάντα ῥεῖ Nov 11 '18 at 00:08
  • 1
    You might also try formatting your code to be use whitespace to make the blocks really apparent. This is helpful for thinking about the code, and it helps other people understand it more quickly. – Omnifarious Nov 11 '18 at 00:12
  • 7
    `std::map` already sorts using `operator – Kevin Nov 11 '18 at 00:28
  • 1
    *I've already read and added them in map* -- Now traverse your map from `map.begin()` to `map.end()` and look at the `first` of the `std::pair` of each elements of the map. Lo and behold, the data is sorted. – PaulMcKenzie Nov 11 '18 at 00:32

2 Answers2

3

The OP wants a custom sort order that's subtly different from the standard lexicographical order. A map with a custom sort order can be achieved by passing in a custom Compare (Compare is the third template parameter of map):

#include <algorithm>
#include <cctype>
#include <cstring>
#include <fstream>
#include <functional>
#include <iostream>
#include <map>
#include <vector>

using std::string;
using std::transform;
using std::map;
using std::cout;

struct Compare {
    bool operator() (const string& s0, const string& s1) const {
        // construct all lowercase versions of s0 and s1
        string str0(s0.length(),' ');
        string str1(s1.length(),' ');
        transform(s0.begin(), s0.end(), str0.begin(), tolower);
        transform(s1.begin(), s1.end(), str1.begin(), tolower);

        if  (!str0.empty() and !str1.empty() and str0.front()==str1.front()) {
            // do a standard lexicographic sort if the first character is the same
            return s0 < s1;
        }
        else {
            // otherwise, do a case-insensitive lexicographic sort using the lowercased strings
            return str0 < str1;
        }
    }
};

typedef map<string, int, Compare> word_count;

int main(){
    word_count wc;
    auto words = { "Abc", "abc", "bag", "Boom", "great"};

    for (auto word : words)
        wc[word]++;

    for(auto elem : wc)
        cout << elem.first << " " << elem.second << '\n';

    return 0;
}

This indeed produces the desired output:

Abc 1
abc 1
Boom 1
bag 1
great 1

Try out a live version of the code online

By default, the third template parameter of a map is less<key> (in this case, less<string>), which will sort strings in the standard lexicographical A-z order.

tel
  • 11,237
  • 2
  • 32
  • 53
1

Here is a complete example with file reading included, and using the base sorting functionality of std::map.

#include <iostream>
#include <cstring>
#include <map>
#include <fstream>

typedef std::map<std::string, int> word_count;

int main(int argc, char** argv){
    if(argc < 2){
        std::cout << "Please provide a file name." << std::endl;
        return 1;
    }

    word_count wc;
    std::ifstream inputfile(argv[1]);

    if (inputfile.is_open()){
        std::string x;
        while(inputfile >> x){
            wc[x]++;
        }
        inputfile.close();
    }else {std::cout << "Program aborted: unable to open input file" << std::endl; return 1;}

    for(auto word: wc){
        std::cout << word.first << "\t" << word.second << std::endl;
    }

    return 0;
}
DVB
  • 31
  • 4