Word Counter Program
/* * This program reads its input and finds all the words. It then counts each * one and produces a report of all the words and counts, ordered by count. * A word is a maximal group of alphanumeric characters. */ #include <cctype> #include <iostream> #include <iomanip> #include <string> #include <vector> #include <map> #include <algorithm> using namespace std; // Sorting function. Used for a sort near the bottom of main to order // the results descending by the count, then ascending by the word within // matching counts. bool order_by_second_descending (map<string,int>::iterator a, map<string,int>::iterator b) { if(a->second == b->second) return a->first < b->first; else return a->second > b->second; } main() { // Map of counts. map<string,int> counts; // Read the input. Read it one character at a time and discard // puntuation to form words. string current_word = ""; char next_char; while(cin.get(next_char)) { if(isalnum(next_char)) { // This a wordish character (letter or digit). Add it // to the current word. current_word += string(1,next_char); } else if(current_word != "") { // The current character is not wordish, but there are // some characters in the current word. So, we need to // add the word to the count. // Look for it. If not found, add it with a count // of 1. Otherwise, increment the count. map<string,int>::iterator loc = counts.find(current_word); if(loc == counts.end()) counts[current_word] = 1; else ++loc->second; // Make sure we don't count this occurrance again. current_word = ""; } } // Now, we have counts for all the words. They're ordered by word, // but we want to order them by count. We could do this by making a // reverse map<int,string> and simply copying all the entries over, // but lets try out another way to do it. // Make a vector for sorting purposes. The vector contains iterators // which point to entries in the map. vector<map<string,int>::iterator> count_order; // Fill it with those iterators to map items. (Think of it as an // array of pointers to all the map pairs.) The reserve asks for more // space, which can be more efficient to do once than have the system // adjust each time it needs more. It doesn't change the size; just // allocates space for future use. count_order.reserve(counts.size()); map<string,int>::iterator i = counts.begin(); for(; i != counts.end(); ++i) count_order.push_back(i); // Now, we sort the list of iterators based on the count and // then the word represented in the map pair they point to. sort(count_order.begin(), count_order.end(), order_by_second_descending); // Print the values in the sorted order descending count, // increasing word within each count value. for(map<string,int>::iterator j: count_order) { cout << setw(8) << right << j->second << " " << left << j-> first << endl; } }
I have refrained from using auto because it's instructive for you to see the types written out. But you can see how convenient auto is. The last loop header could be for(auto j: count_order).