When using a thesaurus, you want to know all the words that
are similar to a particular word. When you look up a word, then, you want a
list of words as the result. Here, the multi containers (multimap or multiset)
are not appropriate. The solution is to combine containers, which is easily
done using the STL. Here, we need a tool that turns out to be a powerful
general concept, which is a map that associates a string with a vector:
//: C07:Thesaurus.cpp
// A map of vectors.
#include <map>
#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <ctime>
#include <cstdlib>
using namespace std;
typedef map<string, vector<string> >
Thesaurus;
typedef pair<string, vector<string> >
TEntry;
typedef Thesaurus::iterator TIter;
// Name lookup work-around:
namespace std {
ostream& operator<<(ostream& os,const
TEntry& t) {
os << t.first << ": ";
copy(t.second.begin(), t.second.end(),
ostream_iterator<string>(os, " "));
return os;
}
}
// A generator for thesaurus test entries:
class ThesaurusGen {
static const string letters;
static int count;
public:
int maxSize() { return letters.size(); }
TEntry operator()() {
TEntry result;
if(count >= maxSize()) count = 0;
result.first = letters[count++];
int entries = (rand() % 5) + 2;
for(int i = 0; i < entries; i++) {
int choice = rand() % maxSize();
char cbuf[2] = { 0 };
cbuf[0] = letters[choice];
result.second.push_back(cbuf);
}
return result;
}
};
int ThesaurusGen::count = 0;
const string ThesaurusGen::letters("ABCDEFGHIJKL"
"MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
// Ask for a "word" to look up:
string menu(Thesaurus& thesaurus) {
while(true) {
cout << "Select a \"word\", 0
to quit: ";
for(TIter it = thesaurus.begin();
it != thesaurus.end(); it++)
cout << (*it).first << ' ';
cout << endl;
string reply;
cin >> reply;
if(reply.at(0) == '0') exit(0); // Quit
if(thesaurus.find(reply) == thesaurus.end())
continue; // Not in list, try again
return reply;
}
}
int main() {
srand(time(0)); // Seed the random number generator
Thesaurus thesaurus;
// Fill with 10 entries:
generate_n(inserter(thesaurus, thesaurus.begin()),
10, ThesaurusGen());
// Print everything:
copy(thesaurus.begin(), thesaurus.end(),
ostream_iterator<TEntry>(cout,
"\n"));
// Create a list of the keys:
string keys[10];
int i = 0;
for(TIter it = thesaurus.begin();
it != thesaurus.end(); it++)
keys[i++] = (*it).first;
for(int count = 0; count < 10; count++) {
// Enter from the console:
// string reply = menu(thesaurus);
// Generate randomly
string reply = keys[rand() % 10];
vector<string>& v = thesaurus[reply];
copy(v.begin(), v.end(),
ostream_iterator<string>(cout, "
"));
cout << endl;
}
} ///:~
Because templates make the expression of powerful concepts
easy, you can take this concept much further, creating a map of vectors
containing maps, and so on. For that matter, you can combine any of the
STL containers this way.