I l@ve RuBoard |
![]() ![]() |
Exercise 3.3Define a map for which the index is the family surname and the key is a vector of the children's names. Populate the map with at least six entries. Test it by supporting user queries based on a surname and printing all the map entries. The map uses a string as an index and a vector of strings for the children's names. This is declared as follows: map< string, vector<string> > families; To simplify the declaration of the map, I've defined a typedef to alias vstring as an alternative name for a vector that contains string elements. (You likely wouldn't have thought of this because the typedef mechanism is not introduced until Section 4.6. The typedef mechanism allows us to provide an alternative name for a type. It is generally used to simplify the declaration of a complex type.) #include <map> typedef vector<string> vstring; map< string, vstring > families; We get our family information from a file. Each line of the file stores the family name and the name of each child: surname child1 child2 child3 ... childN Reading the file and populating the map are accomplished in populate_map(): void populate_map( ifstream &nameFile, map<string,vstring> &families ) { string textline; while ( getline( nameFile, textline )) { string fam_name; vector<string> child; string::size_type pos = 0, prev_pos = 0, text_size = textline.size(); // ok: find each word separated by a space while (( pos = textline.find_first_of( ' ', pos )) != string::npos ) { // figure out end points of the substring string::size_type end_pos = pos - prev_pos; // if prev_pos not set, this is the family name // otherwise, we are reading the children ... if ( ! prev_pos ) fam_name = textline.substr( prev_pos, end_pos ); else child.push_back(textline.substr(prev_pos,end_pos)); prev_pos = ++pos; } // now handle last child if ( prev_pos < text_size ) child.push_back(textline.substr(prev_pos,pos-prev_pos)); if ( ! families.count( fam_name )) families[ fam_name ] = child; else cerr << "Oops! We already have a " << fam_name << " family in our map!\n"; } } getline() is a standard library function. It reads a line of the file up to the delimiter specified by its third parameter. The default delimiter is the newline character, which is what we use. The line is placed in the ssecond parameter string. The next portion of the function pulls out, in turn, the family surname and the name of each child. substr() is a string class operation that returns a new string object from the substring delimited by the two position arguments. Finally, the family is entered into the map if one is not already present. To display the map, we define a display_map() function. It prints entries in this general format: The lippman family has 2 children: danny anna Here is the display_map() implementation: void display_map( const map<string,vstring> &families, ostream &os ) { map<string,vstring>::const_iterator it = families.begin(), end_it = families.end(); while ( it != end_it ) { os << "The " << it->first << " family "; if ( it->second.empty() ) os << "has no children\n"; else { // print out vector of children os << "has " << it->second.size() << " children: "; vector<string>::const_iterator iter = it->second.begin(), end_iter = it->second.end(); while ( iter != end_iter ) { os << *iter << " "; ++iter; } os << endl; } ++it; } } We must also allow users to query the map as to the presence of a family. If the family is present, we display the family name and number of children in the same way that display_map() does for the entire map. (As an exercise, you might factor out the common code between the two functions.) I've named this function query_map(). void query_map( const string &family, const map<string,vstring> &families ) { map<string,vstring>::const_iterator it = families.find( family ); if ( it == families.end() ){ cout << "Sorry. The " << family << " is not currently entered.\n"; return; } cout << "The " << family; if ( ! it->second.size() ) cout << " has no children\n"; else { // print out vector of children cout << " has " << it->second.size() << " children: "; vector<string>::const_iterator iter = it->second.begin(), end_iter = it->second.end(); while ( iter != end_iter ) { cout << *iter << " "; ++iter; } cout << endl; } } The main() program is implemented as follows: int main() { map< string, vstring > families; ifstream nameFile( "C:\\My Documents\\families.txt" ); if ( ! nameFile ) { cerr << "Unable to find families.txt file. Bailing Out!\n"; return; } populate_map( nameFile, families ); string family_name; while ( 1 ){ //!! loop until user says to quit ... cout << "Please enter a family name or q to quit "; cin >> family_name; if ( family_name == "q" ) break; query_map( family_name, families ); } display_map( families ); } The families.txt file contains the following six entries: lippman danny anna smith john henry frieda mailer tommy june franz orlen orley ranier alphonse lou robert brodie When compiled and executed, the program generates the following results. My responses are highlighted in bold. Please enter a family name or q to quit ranier The ranier family has 4 children: alphonse lou robert brodie Please enter a family name or q to quit franz The franz family has no children Please enter a family name or q to quit kafka Sorry. The kafka family is not currently entered. Please enter a family name or q to quit q The franz family has no children The lippman family has 2 children: danny anna The mailer family has 2 children: tommy june The orlen family has 1 children: orley The ranier family has 4 children: alphonse lou robert brodie The smith family has 3 children: john henry frieda |
I l@ve RuBoard |
![]() ![]() |