views:

174

answers:

3
// Write a program to count how many times each distinct word appears in its input. 

#include <iostream>
#include <string>
#include <vector>

int main()
{
    // Ask for 
    // and read the input words
    std::cout << "Please input your words: "
              << std::endl;
    std::vector<std::string> word_input;
    std::string word;
    int count = 0;
    while (std::cin >> word)
        {
            word_input.push_back(word);
            ++count;
        }

    // Compare the input words 
    // and output the times of every word compared only with all the words
    for (int i = 0; i != count; ++i)
        {
            int time = 0;
            for (int j = 0; j != count; ++j)
                {
                    if (word_input[i] == word_input[j])
                        ++time;
                    else
                        break;
                }

            std::cout << "The time of "
                 << word_input[i]
                 << " is: "
                 << time
                 << std::endl;
        }

    return 0;   
}

This is my codes for "Write a program to count how many times each distinct word appears in its input using C++". But I didn't realize the expected funtion. Will someone kind to point how to revise it? THANK YOU!

Sorry, I am new here, and not familiar with stack overflow. Now I will demonstrate in details.

If you compile and run this program, you will see:
Please input your words:
And I input as follows:
good good is good EOF
Then it shows:
The time of good is: 2
The time of good is: 2
The time of is is: 0
The time of good is: 2

But the result doesn't meet what I want.
My expected result is:
The time of good is: 3
The time of is is: 1

And now I think you probably have got what I meant to do.
I think the main problem is at this place:

for (int i = 0; i != count; ++i)
        {
            int time = 0;
            for (int j = 0; j != count; ++j)
                {
                    if (word_input[i] == word_input[j])
                        ++time;
                    else
                        break;
                }

I don't want to use MAP, because I haven't learned that so far. thank you~

+1  A: 

Just delete the else statement.

int main()
{
    // Ask for 
    // and read the input words
    std::cout << "Please input your words: "
              << std::endl;
    std::vector<std::string> word_input;
    std::string word;
    int count = 0;
    while (std::cin >> word)
        {
            word_input.push_back(word);
            ++count;
        }

    // Compare the input words 
    // and output the times of every word compared only with all the words
    for (int i = 0; i != count; ++i)
        {
            int time = 0;
            for (int j = 0; j != count; ++j)
                {
                    if (word_input[i] == word_input[j])
                        ++time;
                    // else          <========== You don't need this!
                    //    break;
                }

            std::cout << "The time of "
                 << word_input[i]
                 << " is: "
                 << time
                 << std::endl;
        }

    return 0;   
}

Note that your solution is very slow for larger inputs. The better idea would be to use hashtable(std::map) for your 'dictionary' or to sort that vector and than count distinct words (runs in O(logN*N), your solution is O(N^2)).

Klark
std::map isn't implemented as a hashtable so it will still be slow. See stdext::hash_map or the newer std::tr1::unordered_map.
Mark Ingram
@Klark:I don't want to use map because I haven't learned that~ I have just learned 3 chapters. And I have justed edited my question. Maybe you didn't get what I want. Thank you all the same~
Eric Wang
@Mark Ingram: Or alternatively `boost::unordered_map` for older compilers.
lunaryorn
@Mark thanks. I 'll check that
Klark
A: 

If you'd prefer to go with a list instead of a map like the others have suggested, then you can use sort before counting so that identical strings are arranged in lexigraphical order. This won't avoid the issues of capitalization unless you want to use a for_each call and a functor to remove all such issues. However, it will allow you to make the solution O(N) for determining count and O(N log N) to do the sort.

list<string> word_input;
while(std::cin >> word){
    word_input( word );
    ++count;
}

word_input.sort();
string holder = word_input.first();
int count = 0;
for(list<string>::const_iterator head = word_input.begin(); head != word_input.end(); ++head ){
    if( head->compare( holder ) ){
        ++count;
    }
    else{
        cout << holder << " has " << count << " appearances." << endl;
        count = 1;
        holder = *head;
    }
}

Note, this code could be shorted substantially but I'm leaving in a manner which I think you'll find most easy to read. I'm assuming you aren't familiar with <algorithm> yet nor <iterator>.

wheaties
+3  A: 

Assuming that std::vector is the only container you're acquainted with at this point, and that you haven't gotten to std::pair yet, I suggest the following:

  • you add a std::vector<int> word_count
  • in your std::cin while-loop, you check if the current word is present in word_input. If it is not, you push_back the word and push_back a 1 in word_count. If there already is an entry for the current word at some index i in word_input, you increment word_count at this index i. Thus every distinct word you input only appears once in word_input, with the number of times it was input being managed in word_count.
  • for output, step through word_input and word_count in parallel and output the word count for every word.

Done.

But all this gets much simpler and more elegant with a std::map. Keep reading! :-)

Christian Severin