/////////////////////////////////////////////////////////////////////////////// // // Exam Score Histogram // // Load a file that defines the categories as strings. // // // Opens a file typed in by user (assumed well formed file with 1 score per line // and scores in range 0 through to 100 (as strings) // // A histogram then plotted of the scores. An "X" per range separed into 0-9, // 10-19...90-99. Scores placed into the groupd based on the first digit. // // Where file name is wrong, error chck in palce to reprompt (using filelib.h) // // File loaded into a vector (that's array in Java speak) // // // Paul Yeatman // 20170911 // // Version Notes: // Initial version (v1.0) // >> Was working and after cleaning the code, I introduce an error where the file // did not read pas the first line. // // Version 2.0 // Makes use of Stanford's filelib.h. Negates the need for me to write my own // GetFilename and OpenFile // /////////////////////////////////////////////////////////////////////////////// /* Two ways to do this: * 1. read the contents of the file into a vector, then examine the data in the vector * 2. read the contents of the file and assign values to relevant vector grid at the same time * NOTE, intialise the vectore so all cells = 0 before option 2 */ #include "console.h" #include "simpio.h" #include "strlib.h" #include "filelib.h" #include #include #include using namespace std; /////////////////////////////////////////////////////////////////////////////// // // Constants should be declared here // /////////////////////////////////////////////////////////////////////////////// const string SCORE_CATEGORIES_FILE = "score_categories.txt"; /*const string STRING_0 = "0-9: "; const string STRING_1 = "10-19: "; const string STRING_2 = "20-29: "; const string STRING_3 = "30-39: "; const string STRING_4 = "40-49: "; const string STRING_5 = "50-59: "; const string STRING_6 = "60-69: "; const string STRING_7 = "70-79: "; const string STRING_8 = "80-89: "; const string STRING_9 = "90-99: "; // put in a vectore instead? arrStringCats[0] assigned to "0-9: " etc. */ const int SCORE_CATEGORIES = 10; /////////////////////////////////////////////////////////////////////////////// // // Variiables should be declared here // /////////////////////////////////////////////////////////////////////////////// /* !! The convention is supposedly adding an i at the start of ints, d for double, * s for string etc. That causes a lot of work if at some time we want to change * the into to a double and we have placed the variable name iNumber multiple times * in the code with and want to change it to a double. dNumber. We could cast it to * a double, but it would be easier to * not put the lower character i,d etc in front. * * If I want to make the code easier to read, the i, d, s etc is the way to go. */ //string sFileName; ifstream inScoreCats; ifstream inScores; vector arrScores; vector arrScoreCategories; vector arrHistogram; /////////////////////////////////////////////////////////////////////////////// // // Typedef section. Create an alias name for another data type. // /////////////////////////////////////////////////////////////////////////////// // typedef vector Coordinates; // this gived vector the name of Coordinates. Used for collecting the mouse click points /////////////////////////////////////////////////////////////////////////////// // // Function Prototypes are declare here here, alternately, just whack all the // methods main calls before main! // // Practically, it's good to list them all at the top, so you do not have to work // out where to place it in the list of functions that are written in the program. // Alternately, put the FP's after Main. // /////////////////////////////////////////////////////////////////////////////// ifstream FileOpenPrompt(); void OpenFile (ifstream inScores); template inline string stringify(const T& input); void BuildHistogram(); void PrintHistogram(); /////////////////////////////////////////////////////////////////////////////// // // DataStructure struct ScoreStats () // // This contains the structure of the data read from he file containing scores // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // Main Program // /////////////////////////////////////////////////////////////////////////////// int main() { openFile(inScoreCats, SCORE_CATEGORIES_FILE); // open file readEntireFile(inScoreCats, arrScoreCategories); // read contents into an array promptUserForFile(inScores, "Enter filename (RETURN to quit): ", "File does not exist, try again:"); readEntireFile(inScores, arrScores); BuildHistogram(); PrintHistogram(); return 0; } /////////////////////////////////////////////////////////////////////////////// // // BuildHistogram // // // Looks at the first character of each vector entry and decides what to do // i.e. if a 1, arrHistogram[1] = arrHistogram[1] +1 // i.e. if a 2, arrHistogram[2] = arrHistogram[1] +1 // // Better coding would be to build up number for an ArrHisto, where each time // a 1 pops up. ArrHisto[1]'s count climbs by one. // /////////////////////////////////////////////////////////////////////////////// void BuildHistogram() { // need to create an empty vectore before calling it. for (int i = 0; i < SCORE_CATEGORIES; i++) { arrHistogram.push_back(""); } int iHistoTracker = 0; for (int i = 0; i < SCORE_CATEGORIES; i++) { for (int j = 0; j < arrScores.size(); j++) { //cout << "Loop " << iHistoTracker << endl; string sArrayContents; sArrayContents = arrScores[j][0]; string siTracker = "" + stringify(iHistoTracker); //cout << siTracker << " is siTracker and " << sArrayContents << " is sArrayContents.\n "; if (sArrayContents == siTracker) { //cout << iHistoTracker << "sArrayContents == siTracker.\n"; /* string sTempHisto = arrHistogram[iHistoTracker]; */ //string sTempHisto; string sTempHisto = arrHistogram[i]; sTempHisto += "X"; arrHistogram[i].assign(sTempHisto); } else { // cout << "sArrayContents != siTracker.\n"; } // without an else, does the next line run regardless? } iHistoTracker ++; } } /////////////////////////////////////////////////////////////////////////////// // // PrintHistogram // // Outputs arrScoreCategories[i] along with arrHistogram[i] on a single line for // for each iteration of the loop // // Working as of 20170913 16:15 PY // /////////////////////////////////////////////////////////////////////////////// void PrintHistogram() { for (int i = 0; i < SCORE_CATEGORIES; i++) { cout << arrScoreCategories[i] << " " << arrHistogram[i] << endl; } // version 2.0 code // // string STRING_ = "STRING_" + stringify(i); // cout << STRING_ << endl; // this outputs STRING_0...STRING_9, however we want the VALUE of the referneced string to be printed. // } /////////////////////////////////////////////////////////////////////////////// // // stringify converts the input to a string. // // From page 729 of C++ All-In_One for dummies // /////////////////////////////////////////////////////////////////////////////// template inline string stringify(const T& input) { ostringstream StringTest; StringTest << input; return StringTest.str(); } /* Pseudo code for void BuildHistogram() string sHisto = 0; for (int i = 0; int < 10; int ++) { what the loop should do... read 1st char of array look at arrScores[0]. if 0, add an x to arrHistogram[0] if 1, add an x to arrHistogram[1] .. if 9, add an x to arrHistogram[9] } The histogram should no be built. // !! can we switch or loop this? Assign the strings as constants? sp STRING_ = STRING_ + 0 gives us STRING_0 which is definfed as "0-9: " } */