0
#include <iostream>
#include <string>
#include <sstream>
#include <map>

int main()
{
    std::string input;
    std::cout << "Enter input: ";
    std::getline(std::cin, input);

    std::map<std::string, int> m;
    std::map<std::string, int>::iterator it;
    std::istringstream iss(input);
    std::string words;

    do {
        iss >> words;
        it = m.find(words);
        if(it != m.end())
        {
            m.insert(it, std::pair<std::string, int>(words, m[words] + 1));
        }
        else
        {
            m.insert(std::pair<std::string, int>(words, 1));
        }
    }while(iss);

    for(std::map<std::string, int>::iterator it = m.begin(); it != m.end(); ++it)
    {
        std::cout << it->first << " - " << it->second << std::endl;
    }
    return 0;
}

The problem is that it prints 1 for every word, even if it appears twice. What could be the problem? I'm not sure if my test for an iterator not to be empty is correct.

Adrian
  • 19,440
  • 34
  • 112
  • 219
  • http://stackoverflow.com/questions/4888879/elegant-ways-to-count-the-frequency-of-words-in-a-file – Robᵩ Mar 19 '11 at 18:17
  • You can also see the other solutions here : [Elegant ways to count the frequency of words in a file](http://stackoverflow.com/questions/4888879/elegant-ways-to-count-the-frequency-of-words-in-a-file) – Nawaz Mar 19 '11 at 18:33

2 Answers2

2

Because map automatically constructs an item with the default constructor, when you access a key that doesn't exist yet, you can simply say:

while (iss >> words) {
    ++m[words];
}

The default value of new items will be 0 (see this question).

Your previous map logic was fine except that you had the condition reversed; it should have been if (it == m.end()) instead of !=, since find() returns end() when the element is not found. As GWW points out in his answer, insert has no effect when the item is already in the map, which is the only time you were using it.

Also, your loop was not handling input properly; you need to check if the state of the stream is invalid after reading in the value, but before using it (since the value is garbage if the stream was at its end). The idiomatic way to handle input is with the while (is >> value) construct; if you want to do it yourself then this is equivalent:

while (true) {
   iss >> words;
   if (!iss) {
       break;
   }

   // Process words...
}

Finally, it's a little misleading to name your variable "words" when it will only contain one word at a time ;-)

Community
  • 1
  • 1
Cameron
  • 96,106
  • 25
  • 196
  • 225
1

I will quote from cplusplus.com.

Because map containers do not allow for duplicate key values, the insertion operation checks for each element inserted whether another element exists already in the container with the same key value, if so, the element is not inserted and its mapped value is not changed in any way.

In your code you are trying to insert on top of an element already in the map. You should change

m.insert(it, std::pair<std::string, int>(words, m[words] + 1));

to

it->second+=1;
GWW
  • 43,129
  • 11
  • 115
  • 108