vectors of vectors representing objects with two dimensions
TRANSCRIPT
Vectors of VectorsVectors of Vectors
Representing ObjectsRepresenting Objects
with Two Dimensionswith Two Dimensions
ProblemProblem
A A seating chartseating chart is often used by teachers to call is often used by teachers to call on students and simplify attendence tracking:on students and simplify attendence tracking:
AlanAbrams
BethBittner
CharlesChalmers
DebraDeVries
EdEvans
FranFerguson
GaryGrodin
HannahHollister
IngmarIllich
JoeJohnson
LouiseLamar
MarkMorris
NancyNorris
ObadiahO’Hare
PamParker
Write a program that reads a seating chart from a file, displays the Write a program that reads a seating chart from a file, displays the chart so that the teacher can call the roll, and writes to a file those chart so that the teacher can call the roll, and writes to a file those who are absent.who are absent.
BehaviorBehavior
Our program should prompt for and read the name Our program should prompt for and read the name of the data file from the user. It should then open of the data file from the user. It should then open an ifstream to that file. It should then read a an ifstream to that file. It should then read a seating chart from that file. The program should seating chart from that file. The program should then prompt for and read the name of an output then prompt for and read the name of an output file, and open an ofstream to that file. The file, and open an ofstream to that file. The program should display the seating chart, and for program should display the seating chart, and for each person listed on it, our program should ask each person listed on it, our program should ask the user if that person is present. If the reply is the user if that person is present. If the reply is ‘n’, the program should write the name of that ‘n’, the program should write the name of that person to the output file. The program should person to the output file. The program should then close the fstreams and display a ‘processing then close the fstreams and display a ‘processing complete’ message.complete’ message.
ObjectsObjects
Description Type Kind NameDescription Type Kind Namein-file name string varying inFileName
input fstream ifstream varying fin
seating chart ??? varying seatingChart
person string varying ???
out-file name string varying outFileName
output fstream ofstream varying fout
reply char varying reply
OperationsOperations
Description Predefined? Library? NameDescription Predefined? Library? Name
display a string yes string <<
read a string yes string >>
open/close fstreams yes fstream --
read seating chart no -- --
print seating chart no -- --
read a char yes -- >>
AlgorithmAlgorithm0. Display purpose of program0. Display purpose of program1. Prompt for and read name of input file into 1. Prompt for and read name of input file into inFileNameinFileName..2. Open 2. Open finfin to to inFileNameinFileName, verify open., verify open.3. Fill 3. Fill seatingChartseatingChart with data from with data from finfin..4. Close 4. Close finfin..5. Display 5. Display seatingChartseatingChart..6. Prompt for and read name of output file into 6. Prompt for and read name of output file into
outFileNameoutFileName..7. Open 7. Open foutfout to to outFileNameoutFileName, verify open., verify open.8. For each student in 8. For each student in seatingChartseatingChart::
a. Ask if they are present.a. Ask if they are present.b. Read b. Read replyreply..c. If c. If replyreply is ‘n’: write the student to is ‘n’: write the student to foutfout..
9. Close 9. Close foutfout..10. Display a ‘processing completed’ message.10. Display a ‘processing completed’ message.
Preliminary AnalysisPreliminary AnalysisSince we are just storing a student’s name, we can use a string to represent student objects.Since we are just storing a student’s name, we can use a string to represent student objects.
A seating chart has two dimensions -- rows and columns -- so we cannot represent it with a simple vector A seating chart has two dimensions -- rows and columns -- so we cannot represent it with a simple vector without losing information.without losing information.
We therefore need to define a class to represent seating chart objects.We therefore need to define a class to represent seating chart objects.
Two-DimensionsTwo-Dimensions
One way to represent a 2-dimensional One way to represent a 2-dimensional structure is to use a structure is to use a vector of vectorsvector of vectors: :
vector< vector<string> > myChart;
Two-DimensionsTwo-Dimensions
One way to represent a 2-dimensional One way to represent a 2-dimensional structure is to use a structure is to use a vector of vectorsvector of vectors: :
vector< vector<string> > myChart;
The “inner” vector represents a row of the chart.The “inner” vector represents a row of the chart.
Two-DimensionsTwo-Dimensions
One way to represent a 2-dimensional One way to represent a 2-dimensional structure is to use a structure is to use a vector of vectorsvector of vectors: :
vector< vector<string> > myChart;
The “inner” vector represents a row of the chart.The “inner” vector represents a row of the chart.
The “outer” vector represents a vector of rows.The “outer” vector represents a vector of rows.
Two-DimensionsTwo-Dimensions
One way to represent a 2-dimensional One way to represent a 2-dimensional structure is to use a structure is to use a vector of vectorsvector of vectors: :
vector< vector<string> > myChart;
The “inner” vector represents a row of the chart.The “inner” vector represents a row of the chart.
The “outer” vector represents a vector of rows.The “outer” vector represents a vector of rows.
The spaces around the “inner” vector are required -- without them, The spaces around the “inner” vector are required -- without them, the compiler may confuse >> with the extraction (input) operator.the compiler may confuse >> with the extraction (input) operator.
Using typedefUsing typedefAlternatively, we can use the Alternatively, we can use the typedef statement to first declare a statement to first declare a RowRow type: type:
typedef vector<string> Row;
and then use this new type to declare our chart: and then use this new type to declare our chart:
vector<Row> myChart;
The The typedef statement has the following pattern: statement has the following pattern: typedef ExistingType NewType;
Its effect is to declare Its effect is to declare NewTypeNewType as a synonym or alias for as a synonym or alias for ExistingTypeExistingType..
It is commonly used to improve program readability. It is commonly used to improve program readability.
Building ClassesBuilding Classes
We can thus start a SeatingChart class as We can thus start a SeatingChart class as follows:follows:class SeatingChart{ public: private:
};
The data members The data members myRowsmyRows and and myColumnsmyColumns are are not required, but they simplify some operations.not required, but they simplify some operations.
int myRows; int myColumns; typedef vector<string> Row; vector<Row> myChart;
PrototypesPrototypesclass SeatingChart{ public:
private: // ... data members omitted};
SeatingChart(); SeatingChart(int rows, int columns); int Rows() const; int Columns() const; string Student(int row, int column) const; friend istream & operator>>(istream & in,
SeatingChart & chart); friend ostream & operator<<(ostream & in,
const SeatingChart & chart);
Operation: Operation: Default ConstructorDefault Constructor
The default constructor initializes the data The default constructor initializes the data members to default values:members to default values:
SeatingChart aChart;
Specification:Specification:Postcondition: Postcondition: myRowsmyRows == 0 && == 0 && myColumnsmyColumns == 0 && == 0 && myChartmyChart.empty() == true..empty() == true.
Default ConstructorDefault Constructor
inline SeatingChart::SeatingChart(){ myRows = 0; myColumns = 0;}
This is simple enough to define This is simple enough to define inlineinline in the header file: in the header file:
The default vector constructor automatically initializes The default vector constructor automatically initializes myChartmyChart as an empty vector< as an empty vector< vector<string> >.vector<string> >.
Explicit-Value ConstructorExplicit-Value Constructor
SeatingChart aChart(3, 5);
This constructor lets you construct a SeatingChart This constructor lets you construct a SeatingChart of a specified size (in rows and columns):of a specified size (in rows and columns):
Specification:Specification:Receive: Receive: rowsrows, , columnscolumns, two int values., two int values.Precondition: Precondition: rowsrows > 0 && > 0 && columnscolumns > 0. > 0.Postcondition: Postcondition: myRowsmyRows == == rowsrows && && myColumnsmyColumns == == columnscolumns
&& && myChartmyChart is a 2-D vector of is a 2-D vector of rowsrows rows and rows and columnscolumns columns.columns.
"" "" "" "" """" "" "" "" """" "" "" "" ""
[0] [1] [2] [3] [4]
[2]
[1]
[0]
myChart
aChart myRowsmyColumns
3
5
Explicit-Value ConstructorExplicit-Value Constructor
// ...#include “SeatingChart.h”
SeatingChart:: SeatingChart(int rows, int columns){ assert(rows > 0 && columns > 0); myRows = rows; myColumns = columns; // build: myChart = vector<Row>(rows); // “outer” vector for (int i = 0; i < rows; i++) // and myChart[i] = vector<string>(columns); // “inner” vectors}
This is sufficiently complicated to define separately:This is sufficiently complicated to define separately:
Explicit-Value ConstructorExplicit-Value Constructor
// ...#include “SeatingChart.h”
SeatingChart:: SeatingChart(int rows, int columns){ assert(rows > 0 && columns > 0); myRows = rows; myColumns = columns; // build: myChart = vector<Row>(rows); // “outer” vector for (int i = 0; i < rows; i++) // and myChart[i] = vector<string>(columns); // “inner” vectors}
This is sufficiently complicated to define separately:This is sufficiently complicated to define separately:
We use one of the three vector constructors to initialize the “outer” vector of We use one of the three vector constructors to initialize the “outer” vector of myChartmyChart..
Explicit-Value ConstructorExplicit-Value Constructor
// ...#include “SeatingChart.h”
SeatingChart:: SeatingChart(int rows, int columns){ assert(rows > 0 && columns > 0); myRows = rows; myColumns = columns; // build: myChart = vector<Row>(rows); // “outer” vector for (int i = 0; i < rows; i++) // and myChart[i] = vector<string>(columns); // “inner” vectors}
This is sufficiently complicated to define separately:This is sufficiently complicated to define separately:
We then use the same vector constructor within a loop to initialize the “inner” vectors of We then use the same vector constructor within a loop to initialize the “inner” vectors of myChartmyChart..
Explicit-Value ConstructorExplicit-Value Constructor
// ...#include “SeatingChart.h”
SeatingChart:: SeatingChart(int rows, int columns){ assert(rows > 0 && columns > 0); myRows = rows; myColumns = columns; // build: myChart = vector<Row>(rows); // “outer” vector for (int i = 0; i < rows; i++) // and myChart[i] = vector<string>(columns); // “inner” vectors}
This is sufficiently complicated to define separately:This is sufficiently complicated to define separately:
This initializes each This initializes each RowRow of of myChartmyChart using the default string constructor (which generates using the default string constructor (which generates empty strings).empty strings).
ExtractorsExtractors
The extractors retrieve data member The extractors retrieve data member values:values:
cout << aChart.Rows() << aChart.Columns();
Specifications:Specifications: Rows:Rows: Return Return myRowsmyRows..
Columns:Columns: Return Return myColumnsmyColumns..
Note that we provide no extractor for Note that we provide no extractor for myChartmyChart, , because it contains the actual seating chart. because it contains the actual seating chart.
Default ConstructorDefault Constructor
inline int SeatingChart::Rows() const{ return myRows;}
These are sufficiently simple to define These are sufficiently simple to define inlineinline::
inline int SeatingChart::Columns() const{ return myColumns;}
Element AccessElement Access
The Student() function returns the student The Student() function returns the student assigned to a given seat:assigned to a given seat:
cout << aChart.Student(r, c);
Specification:Specification:Receive: Receive: rowrow, , columncolumn, two int values., two int values.Precondition: Precondition: rowrow is a valid row-index && is a valid row-index &&
columncolumn is a valid column-index. is a valid column-index. Return: the string in Return: the string in myChartmyChart [ [rowrow][ ][ columncolumn].].
Default ConstructorDefault Constructor
inline string SeatingChart::Student(int row, int column) const{ assert(row >= 0 && row < Rows() && column >= 0 && column < Columns());
return myChart[row][column];}
This is probably simple enough to define This is probably simple enough to define inlineinline::
Note that where a single subscript is used to access an element of a normal vector, two subscripts are needed to access an element of a 2-Dimensional array.Note that where a single subscript is used to access an element of a normal vector, two subscripts are needed to access an element of a 2-Dimensional array.
The first subscript accesses the correct The first subscript accesses the correct RowRow of of myChartmyChart, the second accesses the correct column in that , the second accesses the correct column in that RowRow..
InputInput
fin >> aChart;
The input operator lets you read a The input operator lets you read a SeatingChart:SeatingChart:
Specification:Specification:Receive: Receive: inin, an istream; , an istream; chartchart, a SeatingChart., a SeatingChart.Precondition: Precondition: chartchart is an empty SeatingChart && is an empty SeatingChart && inin leads to a file containing a seating chart. leads to a file containing a seating chart.Input: the seating chart, via Input: the seating chart, via inin..Passback: Passback: inin, the seating chart read from it;, the seating chart read from it; chartchart, containing the extracted values., containing the extracted values.Return: Return: inin, for chaining., for chaining.
Input OperatorInput Operator
// ...istream & operator>>(istream & in, SeatingChart & chart){ string firstName, lastName; // each name is a word char separator; // for end-of-line for (;;) // loop1: { // (to fill outer vector) Row aRow; // declare clean Row for (;;) // loop2: { // (to fill inner vector) in >> firstName >> lastName; // read person’s name in.get(separator); // read white-space if (in.eof()) break; // stop at end-of-file aRow.push_back(firstname + ‘ ‘ + lastName); if (separator == ‘\n’) break;// stop at end-of-line } // end loop2 if (in.eof()) break; // stop at end-of-file chart.push_back(aRow); // append Row to chart } // end loop1 return in; // allow chaining}
This is sufficiently complicated to define separately.This is sufficiently complicated to define separately.
OutputOutput
cout << aChart << endl;
The output operator lets you write a The output operator lets you write a SeatingChart:SeatingChart:
Specification:Specification:Receive: Receive: outout, an ostream; , an ostream; chartchart, a SeatingChart., a SeatingChart.Output: the values in Output: the values in chartchart, via , via outout..Passback: Passback: outout, containing the SeatingChart., containing the SeatingChart.Return: Return: outout, for chaining., for chaining.
Output OperatorOutput Operator
// ...ostream & operator<<(ostream & out, const SeatingChart & chart){ for (int r = 0; r < chart.Rows(); r++) { for (int c = 0; c < chart.Columns(); c++) out << chart.Student(r, c) << ‘\t’; out << ‘\n’; } return out; // allow chaining}
This is sufficiently complicated to define separately.This is sufficiently complicated to define separately.
Such structures are displayed in rows and columns:Such structures are displayed in rows and columns:
Coding Our AlgorithmCoding Our AlgorithmWe are now ready to implement our We are now ready to implement our
algorithm...algorithm...// rollCall.cpp// ... documentation// ... other #includes#include “SeatingChart.h”
int main(){ cout << “\nTo generate the absentee list,” << “\n enter the input file name“ << “\n containing the seating chart: “; string inFileName; cin >> inFileName;
Coding (Coding (Ct’dCt’d))// ... rollCall.cpp continued
ifstream fin(inFileName.data()); assert(fin.is_open());
SeatingChart chart; fin >> chart; fin.close();
cout << “\nEnter the name of the absentee file: “; string outFileName; cin >> outFileName;
ofstream fout(outFileName.data()); assert(fout.is_open());
char reply; // ...
Coding (Coding (Ct’dCt’d))// ... rollCall.cpp continued
for (int r = 0; r < chart.Rows(); r++) for (int c = 0; c < chart.Columns(); c++) { cout << “\nIs “ << chart.Student(r,c) << “ present (y or n)? “; cin >> reply; if (reply == ‘n’) fout << chart.Student << ‘\n’; }
fout.close(); cout << “\nProcessing complete. Results are in “ << outFileName << endl;}
SummarySummaryObjects consisting of values organized in a 2-D structure (i.e., rows and Objects consisting of values organized in a 2-D structure (i.e., rows and
columns) can be represented by a vector of vectors.columns) can be represented by a vector of vectors.
Accessing an element of a vector of vectors requires two subscript Accessing an element of a vector of vectors requires two subscript operations: operations: – one to access the correct element of the “outer” vector (i.e., the correct row); andone to access the correct element of the “outer” vector (i.e., the correct row); and
– one to access the correct element of the “inner” vector (i.e, the correct column one to access the correct element of the “inner” vector (i.e, the correct column within that row).within that row).
If all elements in a 2-D structure must be processed, use If all elements in a 2-D structure must be processed, use two nested for two nested for loopsloops..