Exercise 7-7

Change the driver for the cross-reference program so that it writes line if there is only one line and lines otherwise.

Solution

The solution to this exercise is surprisingly simple. To clarify the question a bit – it essentially asks us to have some sort of if-else condition in place.

For instance…

• If the word “apple” occurs only on one line, we print “apple occurs on line: ” (followed by the line number).
• Otherwise, if the word “apple” occurs on multiple lines, we print “apple occurs on lines: ” (followed by the line numbers).

Recall that the Solution to Exercise 7-3 already provides the skeleton project that reports non-duplicated word occurrence line numbers. It therefore makes sense to use that project as the baseline project, and do the adjustment on top of it.

It turns out that there is only one small bit of code that needs changing, and it resides at the main.cpp file (the main function).

This is the original snippet within the main function:

    // Write the word
cout << it->first << " occurs on line(s): ";


We can change it easily to the following to achieve that if-else conditioning. We essentially resolves the number of non-duplicate line occurences for the word beforehand. We can then use it to construct the if-else logic and display either “line” or “lines” accordingly.

    // Find number of lines the word has appeared
vector<int>::size_type numLines = (it->second).size();

// Write the word
cout << it->first << " occurs on ";
if (numLines == 1)
cout << "line: ";
else
cout << "lines: ";


Surprisingly simple.

The Project

Simply…

1. Re-use that Project as per Solution to Exercise 7-3.
2. Replace the main.cpp file as per followings.
#include <iostream>   // std::cin, std::cout, std::endl
#include <map>        // std::map
#include <string>     // std::string
#include <vector>     // std::vector
#include "xref.h"     // xref

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

// Find all the lines that refer to each word in the input
// (S7.3/128)
int main()
{
// Call xref using split by default.
map<string, vector<int> > ret = xref(cin);

// Write the results.
for (map<string, vector<int> >::const_iterator it = ret.begin();
it != ret.end(); ++it) {

// Find number of lines the word has appeared
vector<int>::size_type numLines = (it->second).size();

// Write the word
cout << it->first << " occurs on ";
if (numLines == 1)
cout << "line: ";
else
cout << "lines: ";

// Followed by one or more line numbers.
vector<int>::const_iterator line_it = it->second.begin();
cout << *line_it;   // write the first line number

++line_it;
// Write the rest of the line numbers, if any.
while (line_it != it->second.end()) {
cout << ", " << *line_it;
++line_it;
}
// Write a new line to separate each word from the next.
cout << endl;
}

return 0;
}


Test Result

Running this new version main code gives us the result as expected.

apple orange banana
orange orange
apple banana
mango
^Z
apple occurs on lines: 1, 3
banana occurs on lines: 1, 3
mango occurs on line: 4
orange occurs on lines: 1, 2


Reference

Koenig, Andrew & Moo, Barbara E., Accelerated C++, Addison-Wesley, 2000