Tuesday, 23 August 2016

Chapter 5 // Exercise 14 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 5 // Exercise 14

Read (day-of-the-week,value) pairs from the standard input. For example:

Tuesday 23 Friday 56 Tuesday -3 Thursday 99

Collect all the values for each day of the week in a vector<int>.Write out the values of the seven day-of-the-week vectors. Print out the sum of the values in each vector. Ignore illegal days of the week such as Funday, but accept common synonyms such as Mon and monday. Write out the number of rejected values.

#include "stdafx.h"
#include "std_lib_facilities_new_version.h"
using namespace std;

void getData();
int checkIllegalDotw();
void printVectors();
void printSum();
vector<int> values;
vector<string> dotw;
vector<string> acceptedDays = { 
"Monday", "monday", "mon", "Mon",
"Tuesday", "tuesday", "tue", "Tue",
"Wednesday", "wednesday", "wed", "Wed",
"Thursday", "thursday", "thurs", "Thurs",
"Friday", "friday", "fri", "Fri",
"Saturday", "saturday", "sat", "Sat",
"Sunday", "sunday", "sun", "Sun" };
int g_rejectedValues = 0;
string g_inputDotw;
int g_inputValues;
int g_n = 0;

int main()
try
{
cout << "Please enter Day of The Week followed by value. Enter from Monday to Sunday: \n";

//get days of the week & values
getData();

//print out both vectors
printVectors();

//print sum & rejected values
printSum();

keep_window_open();

return 0;
}


catch (exception& e)
{
cerr << "Error: " << e.what() << '\n';
keep_window_open();
return 1;
}

//this gets input & checks if g_inputDotw is == to anything within acceptedDays
void getData()
{
while (dotw.size() < 7)
{
cout << "Day of The Week: ";
cin >> g_inputDotw;

g_n = checkIllegalDotw();

while (g_n == 0)
{
cout << "Sorry, that is not an accepted Day of The Week. Try again: \n" << endl;
++g_rejectedValues;
cin >> g_inputDotw;
g_n = checkIllegalDotw();
}

cout << "Value: ";
cin >> g_inputValues;

dotw.push_back(g_inputDotw);
values.push_back(g_inputValues);
}

cout << '\n';
}

//if n is equal to 0 then inputDotw made no matches to anything in acceptedDays
int checkIllegalDotw()
{
for (int i = 0; i < acceptedDays.size(); ++i)
{

if (g_inputDotw == acceptedDays[i])
{
++g_n;
}
}

return g_n;
}

void printVectors()
{
for (int x = 0; x < dotw.size(); ++x)
{
cout << dotw[x] << '\t' << values[x] << '\n';
}
}

void printSum()
{
int sum = 0;

for (int i = 0; i < values.size(); ++i)
{
 
sum += values[i];
}

cout << "The sum of the values is: " << sum << '\n';
cout << "Amount of Week days rejected: " << g_rejectedValues << '\n';
}

It was the omitting illegal days that got me stuck on this one however eventually I created a function which compares the input to each member of the vector that contains allowed days of the week. Basically if inputDotw makes a match to any of those numbers g_n increases making it no longer equal to 0. If it is equal to 0 you know that the input was wrong. I suppose I could've used a bool function for this instead but I still don't feel 100% confident using them yet.

Also, for anyone wondering about the g_ prefix on some variables, it's just to denote that it is a global variable and can therefore be accessed in any part of the code.

EDIT 18/03/2018
As part of exercise 11 in Chapter 7, you are told to revisit 2 programs from chapters 4 or 5. I chose this one as I didn't realise just how much not using bools was holding me back. Here is the new code for this exercise:

#include "stdafx.h"
#include "std_lib_facilities.h"
#include <windows.h>

class ValuePair
{
private:
 //create a name value pair variable
 struct DayValue
 {
  int value;
  string day;
 };

public:
 //functions
 void getValues();
 void printVectors();

 //variables
 DayValue dayvalue;                 //holds int and string pair
 vector<DayValue> dayValueVector;   //vector to store days and values created from struct
 vector<string> acceptedDays = {     //list of days allowed
  "Monday", "monday", "mon", "Mon",
  "Tuesday", "tuesday", "tue", "Tue",
  "Wednesday", "wednesday", "wed", "Wed",
  "Thursday", "thursday", "thurs", "Thurs",
  "Friday", "friday", "fri", "Fri",
  "Saturday", "saturday", "sat", "Sat",
  "Sunday", "sunday", "sun", "Sun" };
 
 int rejectedValues;
 string input;
 int values;
};

//get values, checks for illegal input
void ValuePair::getValues()
{
 bool stop = false;      //to stop loop
 bool allowedDay = false;
 cout << "Please enter a Day of the Week followed by a value. Press 'q' in day to stop.\n";

 //while not 'q' keep getting entries
 while (!stop)
 {
  allowedDay = false;   //reset bool for loop
  cout << ">Day: ";
  cin >> input;

  //if input is q, exit loop to main
  if (input == "q")
  {
   stop = true;
   return;
  }
  else
  {
   //check to see if day is allowed, if allowed set to true, if not ++ rejected value
   for (int i = 0; i < acceptedDays.size(); ++i)
   {
    if (input == acceptedDays[i])
    {
     allowedDay = true;
     dayvalue.day = input;
    }
   }

   //get a value
   cout << ">Value: ";
   cin >> values;
   //if not a number, keep looping til number entered
   while (!cin)
   {
    ++rejectedValues;
    cin.clear();    //reset stream
    cin.ignore(10000, '\n'); //ignore everything entered till newline
    cout << "Not a number, try again > ";
    cin >> values;
   }

   //if day was valid pushback both values, if not ++rejected values and don't pushback
   if (allowedDay)
   { 
    dayvalue.value = values;
    dayValueVector.push_back(dayvalue);  //push values back into vector
   }
   else
    ++rejectedValues;
  }
 }
}

//print the valid values in vector as well as sum and rejected values
void ValuePair::printVectors()
{
 int value = 0;

 for (int i = 0; i < dayValueVector.size(); ++i)
 {
  cout << "Day: " << dayValueVector[i].day << "   Value: " << dayValueVector[i].value << endl;
  value += dayValueVector[i].value;
 }

 cout << "\nSum of all Values: " << value << endl;
 cout << "Number of Rejected Values: " << rejectedValues << endl;
}

ValuePair dayAndValue;

//start main program
int main()
{
 //get values and check them
 dayAndValue.getValues();

 //print the vector and the sum of all values
 dayAndValue.printVectors();

 //keep the the window open
 keep_window_open();

 return 0;
}


This now handles all errors. Also instead of the very confusing way I was checking for illegal input before, now I check the input against the allowed values and if it finds one, it sets a bool to true. Only when this bool is true will it pushback both values into the vector, if not it will still ask for a value but ignore them as per what is asked for.

EDIT 30/09/2019

What a mess these previous answers were. Here is the new code: https://github.com/l-paz91/principles-practice/blob/master/Chapter%205/Exercise14

It doesn't have fancy checking, i.e it expects numbers for number input (or it will throw a runtime error) but I have no idea what was going through my mind 3 years ago.

7 comments:

  1. I did this one using bool function.
    Very Easy and less complicated!

    #include "../../std_lib_facilities.h"

    int main()
    try
    {

    vector day = { "Monday", "monday", "mon", "Mon",
    "Tuesday", "tuesday", "tue", "Tue",
    "Wednesday", "wednesday", "wed", "Wed",
    "Thursday", "thursday", "thurs", "Thurs",
    "Friday", "friday", "fri", "Fri",
    "Saturday", "saturday", "sat", "Sat",
    "Sunday", "sunday", "sun", "Sun" };


    vector days;
    vector day_number;

    int sum = 0;

    string day_name;
    int day_num = 0;

    int reject = 0;

    cout << "Write your day name and day number. \n";

    int d = 1;

    while (d<=7)

    {
    cin >> day_name>> day_num;

    bool ok = false;

    for (int i = 0; i < day.size(); ++i)
    {
    if (day_name == day[i])
    {
    days.push_back(day_name);
    day_number.push_back(day_num);
    ok = true;
    ++d;
    }

    }

    if (ok == false)
    {
    cout << "Invalid day name. Try Again!\n";
    ++reject;
    }



    }

    for (int i = 0; i < day_number.size(); ++i)
    sum = sum + day_number[i];

    for (int i = 0; i < 7; ++i)
    cout << '\n' << days[i] << '\t' << day_number[i] << '\n';

    cout << "Total sum of number of days = " << sum << '\n';

    cout << "Total rejected values: " << reject << '\n';

    keep_window_open("~");

    }


    catch (exception& e)
    {
    cerr << "error: " << e.what() << '\n';
    keep_window_open();
    return 1;
    }
    catch (...) {
    cerr << "Oops: unknown exception!\n";
    keep_window_open();
    return 2;
    }


    ReplyDelete
  2. Blogspot omitted my comment:

    vector day = { "Monday", "monday", "mon", "Mon",
    "Tuesday", "tuesday", "tue", "Tue",
    "Wednesday", "wednesday", "wed", "Wed",
    "Thursday", "thursday", "thurs", "Thurs",
    "Friday", "friday", "fri", "Fri",
    "Saturday", "saturday", "sat", "Sat",
    "Sunday", "sunday", "sun", "Sun" };


    vector days;
    vector day_number;

    ReplyDelete
  3. It did it again....

    WHY IS IT DELETING string between conical brackets?

    vector "<" string ">" day = { "Monday", "monday", "mon", "Mon",
    "Tuesday", "tuesday", "tue", "Tue",
    "Wednesday", "wednesday", "wed", "Wed",
    "Thursday", "thursday", "thurs", "Thurs",
    "Friday", "friday", "fri", "Fri",
    "Saturday", "saturday", "sat", "Sat",
    "Sunday", "sunday", "sun", "Sun" };


    vector "<" string ">" days;
    vector "<" int">" day_number;




    ReplyDelete
    Replies
    1. It's ok, the comment sections on most places don't really support code, I understand what your trying to do though :).

      This is awesome, much less code, you should try splitting it up now into separate functions so it's not all in main. Like I said, bools throw me a little so I tend to avoid them, making my life more difficult for myself.

      Delete
  4. What does g_ means?

    ReplyDelete
    Replies
    1. I mention it at the bottom of my comments (they are in green), basically, I'm trying to get into the habit of pre-fixing global variables with g_(variablename). This is because global variables shouldn't really be used as they can be accessed anywhere from within the code (if you have them set to external as well) and if another programmer has to amend your work they could end up changing this variable. I don't always do it as I'm trying to avoid the use of global variables.

      Delete
  5. You can stop the loop right away when you find a match

    int checkIllegalDotw()
    {
    for (int i = 0; i < acceptedDays.size(); ++i)
    {

    if (g_inputDotw == acceptedDays[i])
    {
    ++g_n;
    }
    }

    return g_n;
    }

    ReplyDelete