Function to output words in a vector and the occurrence.

Discussion in 'C++' started by Xernoth, Apr 20, 2007.

  1. Xernoth

    Xernoth Guest

    Hi,

    I have an exercise that requests the following:

    Write a function that reads words from an input stream and stores them
    in a vector.
    Use that function both to write programs that count the number of
    words in the input,
    and to count how many times each word occurred.

    The below code works fine, but would like some advice on the
    occurrence count.

    I have commented out the part that concerns me.

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

    using std::cin;
    using std::cout;
    using std::endl;
    using std::istream;
    using std::string;
    using std::vector;

    istream& read(istream& in, vector<string>& words)
    {
    if (in)
    {
    words.clear();
    string temp;
    while (in >> temp)
    words.push_back(temp);

    in.clear();
    }
    return in;
    }

    int main()
    {
    cout << "Enter a list of words:" << endl;

    vector<string> words;
    read(cin, words);

    vector<string>::size_type vecSize = words.size();

    cout << "You entered " << vecSize << " words." << endl;

    for (vector<string>::size_type i = 0; i < vecSize; i++)
    {
    int wordCount = 0;
    for (vector<string>::size_type j = 0; j < vecSize; j++)
    {
    if (words == words[j])
    {
    wordCount += 1;
    //if (wordCount > 1)
    //{
    // words.erase(words.begin() + j);
    // vecSize = words.size();
    //}
    }
    }
    cout << "The word: " << words << " occured " << wordCount
    << " times." << endl;
    }

    return 0;
    }

    With that portion of code commented, let's say I have an input with
    the words:

    "This that then that"

    My output will appear as:

    You entered 4 words.
    The word: this occured 1 times.
    The word: that occured 2 times.
    The word: then occured 1 times.
    The word: that occured 2 times.

    With the code uncommented, the output appears as:
    You entered 4 words.
    The word: this occured 1 times.
    The word: that occured 2 times.
    The word: then occured 1 times.

    Which is what I am after, but is commented code a poor method to
    achieve this effect?

    I have done a search and made a note of some responses using a
    container of <string, int>, but the book I am following has not
    covered this aspect.
    Also I am aware of the use of size_t over ::size_type, but the book
    has it's own method and am using that for the time being. It has also
    not covered the use of ::iterator just yet.

    Any advice is appreciated.
    Xernoth, Apr 20, 2007
    #1
    1. Advertising

  2. Xernoth

    Jim Langston Guest

    "Xernoth" <> wrote in message
    news:...
    > Hi,
    >
    > I have an exercise that requests the following:
    >
    > Write a function that reads words from an input stream and stores them
    > in a vector.
    > Use that function both to write programs that count the number of
    > words in the input,
    > and to count how many times each word occurred.
    >
    > The below code works fine, but would like some advice on the
    > occurrence count.
    >
    > I have commented out the part that concerns me.
    >
    > #include <iostream>
    > #include <vector>
    > #include <string>
    >
    > using std::cin;
    > using std::cout;
    > using std::endl;
    > using std::istream;
    > using std::string;
    > using std::vector;
    >
    > istream& read(istream& in, vector<string>& words)
    > {
    > if (in)
    > {
    > words.clear();
    > string temp;
    > while (in >> temp)
    > words.push_back(temp);
    >
    > in.clear();
    > }
    > return in;
    > }
    >
    > int main()
    > {
    > cout << "Enter a list of words:" << endl;
    >
    > vector<string> words;
    > read(cin, words);
    >
    > vector<string>::size_type vecSize = words.size();
    >
    > cout << "You entered " << vecSize << " words." << endl;
    >
    > for (vector<string>::size_type i = 0; i < vecSize; i++)
    > {
    > int wordCount = 0;
    > for (vector<string>::size_type j = 0; j < vecSize; j++)
    > {
    > if (words == words[j])
    > {
    > wordCount += 1;
    > //if (wordCount > 1)
    > //{
    > // words.erase(words.begin() + j);
    > // vecSize = words.size();
    > //}
    > }
    > }
    > cout << "The word: " << words << " occured " << wordCount
    > << " times." << endl;
    > }
    >
    > return 0;
    > }
    >
    > With that portion of code commented, let's say I have an input with
    > the words:
    >
    > "This that then that"
    >
    > My output will appear as:
    >
    > You entered 4 words.
    > The word: this occured 1 times.
    > The word: that occured 2 times.
    > The word: then occured 1 times.
    > The word: that occured 2 times.
    >
    > With the code uncommented, the output appears as:
    > You entered 4 words.
    > The word: this occured 1 times.
    > The word: that occured 2 times.
    > The word: then occured 1 times.
    >
    > Which is what I am after, but is commented code a poor method to
    > achieve this effect?
    >
    > I have done a search and made a note of some responses using a
    > container of <string, int>, but the book I am following has not
    > covered this aspect.
    > Also I am aware of the use of size_t over ::size_type, but the book
    > has it's own method and am using that for the time being. It has also
    > not covered the use of ::iterator just yet.
    >
    > Any advice is appreciated.


    Well, you didn't specify what tools you were allowed to use. If you are
    allowed to use std::map it becomes extremely easy. Consider.

    std::map<std::string, int> WordCount;
    // for loop
    WordCount[words]++;

    This one line of code does a whole bunch of things. You can add an entry to
    a map by specifing a key that doesn't already exist in []. Then it would
    increment it. A map has it's data part (.second) default constructued, for
    an int it means it would be 0.

    So... if WordCount[words] doesn't exist, it adds it to the map, makes the
    int 0, then increments it becuase of the ++ post increment.
    If it already exists, it simply increments it.

    When you are done iteratring through your words, you have a map keyed by the
    word where the value is the number of times it appeared.

    Iterate through the map when you are done to dispaly the values.
    Jim Langston, Apr 20, 2007
    #2
    1. Advertising

  3. Xernoth

    Xernoth Guest

    On Apr 20, 12:53 am, "Jim Langston" <> wrote:
    > Well, you didn't specify what tools you were allowed to use. If you are
    > allowed to use std::map it becomes extremely easy. Consider.
    >
    > std::map<std::string, int> WordCount;
    > // for loop
    > WordCount[words]++;


    Yes, this is what I read on another post as a solution, however the
    book has not yet covered ::map. For the record, it's the Accelerated C+
    + book. Chapter 4, exercise 4-5.
    Xernoth, Apr 20, 2007
    #3
  4. On 20 Apr, 01:32, Xernoth <> wrote:
    > Hi,
    >
    > I have an exercise that requests the following:
    >
    > Write a function that reads words from an input stream and stores them
    > in a vector.
    > Use that function both to write programs that count the number of
    > words in the input,
    > and to count how many times each word occurred.
    >
    > The below code works fine, but would like some advice on the
    > occurrence count.
    >
    > I have commented out the part that concerns me.
    >
    > #include <iostream>
    > #include <vector>
    > #include <string>
    >
    > using std::cin;
    > using std::cout;
    > using std::endl;
    > using std::istream;
    > using std::string;
    > using std::vector;
    >
    > istream& read(istream& in, vector<string>& words)
    > {
    > if (in)
    > {
    > words.clear();
    > string temp;
    > while (in >> temp)
    > words.push_back(temp);
    >
    > in.clear();
    > }
    > return in;
    >
    > }
    >
    > int main()
    > {
    > cout << "Enter a list of words:" << endl;
    >
    > vector<string> words;
    > read(cin, words);
    >
    > vector<string>::size_type vecSize = words.size();
    >
    > cout << "You entered " << vecSize << " words." << endl;
    >
    > for (vector<string>::size_type i = 0; i < vecSize; i++)
    > {
    > int wordCount = 0;
    > for (vector<string>::size_type j = 0; j < vecSize; j++)
    > {
    > if (words == words[j])
    > {
    > wordCount += 1;
    > //if (wordCount > 1)
    > //{
    > // words.erase(words.begin() + j);
    > // vecSize = words.size();
    > //}
    > }
    > }
    > cout << "The word: " << words << " occured " << wordCount
    > << " times." << endl;
    > }
    >
    > return 0;
    >
    > }
    >
    > With that portion of code commented, let's say I have an input with
    > the words:
    >
    > "This that then that"
    >
    > My output will appear as:
    >
    > You entered 4 words.
    > The word: this occured 1 times.
    > The word: that occured 2 times.
    > The word: then occured 1 times.
    > The word: that occured 2 times.
    >
    > With the code uncommented, the output appears as:
    > You entered 4 words.
    > The word: this occured 1 times.
    > The word: that occured 2 times.
    > The word: then occured 1 times.
    >
    > Which is what I am after, but is commented code a poor method to
    > achieve this effect?


    I'm not sure how much better it it but it would reduce the code to a
    single loop if you first sorted the vector (using std::sort()) and
    then went through the vector and took notice of when the word changed,
    something like this (totally untested):

    cout << "You entered " << vecSize << " words." << endl;

    sort(words.begin(), words.end())

    string currentWord = words[0];
    int wordCount = 0;
    for (vector<string>::size_type i = 0; i < vecSize; i++)
    {
    if (words == currentWord)
    ++wordCount;
    else
    {
    cout << "The word: " << currentWord << " occured " << wordCount <<
    " times\n";
    wordCount = 1;
    currentWord = words;
    }
    }

    --
    Erik Wikström
    =?iso-8859-1?q?Erik_Wikstr=F6m?=, Apr 20, 2007
    #4
  5. Xernoth

    utab Guest

    > I'm not sure how much better it it but it would reduce the code to a
    > single loop if you first sorted the vector (using std::sort()) and
    > then went through the vector and took notice of when the word changed,
    > something like this (totally untested):


    You are not the only one who thought that :)) when I was reading that
    book I tried out sth like this:

    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <vector>
    int main(){

    std::string x;
    std::vector<std::string> input;
    std::vector<std::string> sorted_input;
    std::vector<std::string> words;
    std::vector<int> counts;
    std::vector<std::string>::size_type vec_sz;
    int count=1;


    while(std::cin >> x)
    input.push_back(x);

    sort(input.begin(),input.end());

    std::string test=input[0];

    vec_sz=input.size();

    for(unsigned i=0;i!=vec_sz;++i)
    std::cout << input << std::endl;


    for(unsigned k=1;k!=vec_sz;++k){

    if(input[k]==test){
    ++count;
    if(k==vec_sz-1){
    words.push_back(test);
    counts.push_back(count);
    }
    }
    else{
    words.push_back(test);
    counts.push_back(count);
    test=input[k];
    count=1;
    if(k==vec_sz-1){
    words.push_back(test);
    counts.push_back(count);
    }
    }
    }
    vec_sz=words.size();
    std::cout << "WORDS" <<"\t"<<"OCCURENCE#"<<std::endl;
    for(unsigned i=0;i!=vec_sz;++i)
    std::cout << words<<"\t" << counts<< std::endl;

    return 0;

    }


    Hope it helps, feel free to experiment on the code... not the elegant
    way to accomplish the task but a humble different approach.

    Greetings,
    utab, Apr 20, 2007
    #5
  6. Xernoth

    Xernoth Guest

    On Apr 20, 7:18 am, Erik Wikström <> wrote:
    > I'm not sure how much better it it but it would reduce the code to a
    > single loop if you first sorted the vector (using std::sort()) and
    > then went through the vector and took notice of when the word changed,
    > something like this (totally untested):


    utab wrote:
    > You are not the only one who thought that :)) when I was reading that
    > book I tried out sth like this:


    Thanks to both of you. That seems like a good approach, and more to
    what the book is looking for, since it does not cover the use of any
    extra functions for vectors.
    I'll give that a try, but looking over the code, will seem to do just
    what I'm after.
    Xernoth, Apr 20, 2007
    #6
  7. Xernoth

    Jerry Coffin Guest

    In article <>,
    says...

    [ ... ]

    > > With the code uncommented, the output appears as:
    > > You entered 4 words.
    > > The word: this occured 1 times.
    > > The word: that occured 2 times.
    > > The word: then occured 1 times.
    > >
    > > Which is what I am after, but is commented code a poor method to
    > > achieve this effect?


    I'd do this a bit differently, something like this:

    // Warning: this code has received only minimal testing.
    //
    typedef std::pair<std::string, int> word_count;

    namespace std {
    // I believe putting this in ::std is officially cheating, but...
    std::eek:stream &operator<<(std::eek:stream &os, word_count const &p) {
    os << "The word: " << p.first
    << " occurred " << p.second << " times.";
    return os;
    }
    }

    void count(std::istream &in, std::eek:stream &out) {
    std::map<std::string, int> word_counts;

    std::string temp;

    while (in >> temp)
    ++word_counts[temp];

    std::copy(word_counts.begin(), word_counts.end(),
    std::eek:stream_iterator<word_count>(out, "\n"));
    }

    Another possibility would be to collect the words in a multiset, and
    then use std::equal_range and std::distance to produce the output.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Apr 21, 2007
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. pmatos
    Replies:
    6
    Views:
    23,724
  2. Replies:
    8
    Views:
    1,890
    Csaba
    Feb 18, 2006
  3. Jack
    Replies:
    8
    Views:
    138
  4. Peng Yu
    Replies:
    5
    Views:
    164
    Jürgen Exner
    Jan 25, 2010
  5. David Karr
    Replies:
    4
    Views:
    188
    Ben Bacarisse
    Sep 16, 2013
Loading...

Share This Page