-1

I'm trying to write a program for every word in stdin, output a list of pairs of the form L:N where L is a line number and N is the number of occurrences of the given word.

So if stdin is:

hello world
hello hello

the output should be

hello 1:1 2:2
world 1:1

In the code below

#include <iostream>
#include <map>
#include <string>
#include <iterator>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::map;
using std::pair;


int main(int argc, const char *argv[])
{
    map<string, pair<unsigned int, unsigned int>> table;
    string word;
    while (cin >> word) {
        ++table[word];
    }
    for (std::map<string, pair<unsigned int, unsigned int>>::iterator itr = table.begin(); itr != table.end();
        ++itr) {
        cout << itr->first << "\t => \t" << itr->second << itr->third << endl;
    }
    while (cin >> word) {
        ++table[word];
    }
}

I'm trying to make a map that uses three elements and have an iterator that can traverse through the map as well as count the number of lines and use getline() to get the number of occurrences of a word on each line. This code just outputs just the total word count.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129

2 Answers2

0

To help get you started, I suggest you use a map with a structure for the line number and occurrences:

struct Word_Attributes
{
  unsigned int line_number;
  unsigned int occurances_on_line;
};

typedef std::vector<Word_Attributes> Attribute_Container;

typedef std::map<string, Attribute_Container> Dictionary;  

int main(void)
{
  Dictionary  my_words;
  std::string text_line;
  unsigned int line_number = 1;
  // Read in text lines until EOF or failure.
  while (getline(cin, text_line)
  {
    // Extract words from the text line.
    std::string        word;
    std::istringstream text_stream(text_line);
    while (text_stream >> word)
    {
      // A word is extracted.  
      // See if it is in the dictionary.
      Dictionary::iterator  iter;
      iter = my_words.find(word);

      // If the word is in the dictionary, check for attributes.
      if (iter != my_words.end())
      {
        // use iter to get the property list.
        // Check the property list for the line number.
        // If line number exists, increment the occurrances.
        // Otherwise, create a new attributes structure and
        //    append to the property list.
      }
      else
      {
        // The word is not in the dictionary,
        //   create an initial attributes structure for the word.
        Word_Attributes  attributes;
        attributes.line_number = line_number;
        attributes.occurances_on_line = 1;
        Attribute_Container  property_list;
        property_list.push_back(attributes);
        my_words[word] = property_list;
      }
    }
  }
  return EXIT_SUCCESS;
}

Here are some properties / rules:

  • Every word has one or more line numbers associated with the word.
  • Every line number, of the word, has a number of occurrences.

For the input of:

[1]  hello world
[2]  hello hello

You should see:

hello ---> Line 1, occurrences: 1  
  |   +--> Line 2, occurrences: 2  
  V
world ---> Line 1, occurrences: 1

Completing the stencil above is an exercise for the reader.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
0

I would use this container to represent the data:

//           word               line   count
std::map<std::string, std::map<size_t, size_t>> wordCounts;

The inner map would be more optimal as a cheaper data structure, however depending on your performance requirements you might like to go with this because it's very easy to work with (you need to write less code). For example, when you parse a new word and have its line number this is all you have to do to update the data structure:

++wordCounts[word][lineNumber];

Doesn't get much simpler than that. If the word or line number isn't in the structure already it adds it, if it is, it uses what's already there.

Filling it in would look something like this:

std::string line;
for(size_t lineNumber = 1; std::getline(std::cin, line); ++lineNumber)
{
    std::istringstream ss{line}
    for(std::string word; ss >> word;)
        ++wordCounts[word][lineNumber];
}
David
  • 27,652
  • 18
  • 89
  • 138