Link to home
Start Free TrialLog in
Avatar of vlahomt
vlahomt

asked on

loop analyzing sales data

I am supposed to import a data file and then display the data then state what is the highest sales amount and how many times it occurs and what is the second highest sales amount and how many times it occurs.

I can get the highest amount correctly and the second highest amount sometimes depending on where it is in the order of the data.

however i can not get the occurance times correct at all.

here is my code.
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>

using namespace std;

int main ()
{
      int id, counter, counter2;
      double sales;
      char* header;
      char* header2;
      char* header3;
      double high_sales, temp, second_high_sales;
      counter = 0;
      counter2 = 0;
      high_sales = 0;
      second_high_sales = 0;

      header = "  Acme Sales Report    ";
      header2= "  ID         Sales      ";
      header3= "  __         _____      ";
      
      cout << fixed <<setprecision(2);

      ifstream infile ("sales3.txt");

      if (!infile){
                  cout << "Can not open file";
            return 1;
      }

      while (infile >> id >> sales){
            cout << id << "      " << setw(8) << sales << endl;
            if (sales > high_sales){
                  temp = high_sales;
                  high_sales = sales;
            }
            if (sales == high_sales)
                  counter++;
            
            if (temp > second_high_sales){
                  second_high_sales = temp;
                  counter2++;
            }
      }
      cout << "The highest sales amount is " << setw(8) << high_sales << " it occurs " << counter << " times" << endl;
      cout << "Second High Sales are " << setw(8) << second_high_sales << " it Occurs " << counter2 << " times" << endl;


return 0;
}

here are the contents of the 1st data file.

1000  1000
1111   500
1500  1000
2000   900
2222  2000
2500  2000
3000  1500
3333  2000
3500  2000
4000   600
4444  2500
4500  2000
5000  2500
5500  2222
5555  2000
6000  1999
6500  2222
6666  2500
7000   100
7500  2100
7777  2150


here are the contents of the second data file

1000  1000
1111   500
1500  1000
2000   900
2222  2000
2500  2000
3000  1500
3333  2000
3500  2000
4000   600
4444  2500
4500  2000
5000  2500
5500  2222
5555  2000
6000  1999
6500  2222
6666  2500
7000   100
7500  3000
7777  2150


here are the contents of the third data file

1000  1000
1111  1000
1500  1000
2000  1200
2222  1200
2500  1500
3000  1500
3333  1500
3500  1000
4000  1500
4444  1500
4500  2000
5000  4000
5500  2000
5555  4000
6000  2000
6500  2000
6666  2000
7000   100
7500  3000
7777  4000


This was a homework problem but it was due at 11:00pm central time today so I just turned in what I had above hoping for partial credit.
I would like to know how to solve this problem though for future referance.



Avatar of efn
efn

I think you can find the bugs if you hand-simulate the program.  Process some input data keeping track of the values on paper following the logic of your program.  Or use a debugger if you have one available.

A few hints:

When you hit a new high, you have only seen one of that value, so start a new count.

When you demote a high to second-highest, don't forget to bring along the old high's count.

Count an occurrence of the second-highest value when you read one of that value, not when you demote the high value.

It should be possible for the second-highest value to change without demoting the highest.
1. First of  initialize temp also
temp = 0;

2. reset counter for high_sale

 if (sales > high_sales){
               temp = high_sales;
               high_sales = sales;
          }

Here you have updated the new highest value but didn't reset the counter....

make counter = 0 in the above if condition

 if (sales > high_sales){
               temp = high_sales;
               high_sales = sales;
               counter = 0;
          }
 else {
 temp =0;
 }

 if (sales == high_sales)
               counter++;

will increase it....


3. for second highest

      if (temp > second_high_sales){
               second_high_sales = temp;
               counter2++;
      }


use following

if (sales > second_high_sales)
{
     if(temp != 0){
               second_high_sales = temp;
               counter2 = 1;
     }
}
else if (sales == second_high_sales)
{
             counter2++;
}

============================

Finally

while (infile >> id >> sales)
{
          cout << id << "      " << setw(8) << sales << endl;
          if (sales > high_sales)
          {
               temp = high_sales;
               high_sales = sales;
               counter = 0;
          }
          else
          {
            temp = 0;
          }

          if (sales == high_sales)
               counter++;
         
          if (sales > second_high_sales)
          {
                if(temp != 0)
                {
                  second_high_sales = temp;
                  counter2 = 1;
               }
          }
          else if (sales == second_high_sales)
          {
             counter2++;
          }
}
I took your code and made some comments and added a different approach.

Not so much because the code posted was bad but to show you some advanced and improved techniques.

I give full (tested) code though it is a homework question. That is because the asker already posted full code himself and cause it would make no sense to propagate advanced techniques not giving the code.

Regards, Alex
 

#include <iostream>
#include <iomanip>
// you don't need cmath or math.h for normal arithmetics
// #include <cmath>
#include <fstream>

// you could omit plain char pointers by that
#include <string>

// allows you to read the input file line by line
// and convert numbers by using strings rather than
// converting them when reading
#include <sstream>

// vector is a dynamic array class to store the data
// for further evaluation rather than evaluating the data
// directly when reading
#include <vector>

// sort template function
#include <algorithm>

using namespace std;

// a structure allows you to create a new data type.
struct Sales
{
    int id;
    int sales;   // I didn't see any floating point number
                 // so I start with an int ???

    // that overload is for sorting Sales items by sales value
    bool operator<(const Sales& s)
    {
        return sales < s.sales;
    }
};

// modular programming means you should use an own function
// for any new task

// read the input file and return all values in vector salesArr
// return true if successful
bool readData( const string& filename, vector< Sales >& salesArr )
{
     // c_str returns a const char * for the std::string
     ifstream infile ( filename.c_str() );

     if (!infile)
     {
          cout << "Can not open file >>" << filename << "<<" << endl;
          return false;
     }

     // we read the file line by line
     // that makes it easier to ignore white spaces
     // or spot errors in input data

     int counter = 0;
     string line;
     while (getline(infile, line))
     {
         // ignore empty lines
         if (line.empty())
             continue;

         ++counter;
         // string streams make it easier to read wrong data
         // by not spoiling the file stream
         istringstream iss(line);

         // we read the values from the string and display errors if any
         Sales sales = { 0 };
         if (!(iss >> sales.id))
         {
             cout  << ">>" << line << "<<, Error reading line " << counter << ". The id can not be read properly. " << endl;
             return false;
         }
         if (!(iss >> sales.sales))
         {
             cout  << ">>" << line << "<<, Error reading line " << counter << ". The sales value can not be read properly. " << endl;
             return false;
         }
         // put the Sales to the vector
         salesArr.push_back(sales);
     }
     return true;
}

// output the data read
void displayData( const vector<Sales>& salesArr)
{
     // you didn't use the header constants in your code!
     // use const whereever possible
     const string header1 = "  Acme Sales Report    ";
     const string header2 = "  ID         Sales      ";
     const string header3 = "  __         _____      ";

     cout << header1 << endl << header2 << endl << header3 << endl;

     // not really necessary for integer salesArr ???
     cout << fixed << setprecision(2);

     for (int i = 0; i < salesArr.size(); ++i)
     {
         const Sales& sales = salesArr[i];
         cout << sales.id << "   " << sales.sales << endl;
     }
     cout << endl;
}


// get highest and second highest salesArr
void evaluateDisplayTopTwoSales(  const vector<Sales>& inputArr )
{
    if (inputArr.empty())
        return;  // ???

    // make a local copy where we have write access
    vector<Sales> salesArr = inputArr;
    // we sort the Sales items by sales value (in ascending order)
    // here operator< was used
    sort( salesArr.begin(), salesArr.end() );

    // now its easy to evaluate and display the highest sales values
    // we do it in a loop to have one piece of code for highest and
    // second highest
    string prompt = "The highest sales amount is      ";
    for (int i = 0; i < 2; ++i)
    {
        int nsiz        = salesArr.size();
        int high_sales  = salesArr[nsiz-1].sales;
        int counter  = 0;
        while (--nsiz >= 0)
        {
            Sales& sales = salesArr[nsiz];
            if (sales.sales != high_sales)
                break;
            // count occurrence
            ++counter;
            // erase last from array
            salesArr.resize(nsiz);
        }

        cout << prompt << setw(8) << high_sales << " it occurs " << setw(3) << counter << " times" << endl;

        prompt = "The next highest sales amount is ";
        if (nsiz == 0)
            break;   // just for case where we have only one value
    }
}

// finally we put all together
int main ()
{
     // create an empty vector
     vector<Sales> salesArr;

     if (!readData("sales3.txt", salesArr) )
         return 1;

     displayData(salesArr);

     evaluateDisplayTopTwoSales(salesArr);

     return 0;
}


Avatar of vlahomt

ASKER

Everything that jitendra_wadhwani works except for finding the second high value. what itsmeandnobodyelse said is way beyond my level of understanding I have not learned how to work with array's yet that is next week.

I have tried to follow the logic and see why it is not finding the second high value correctly but I am not sure.
jitendra_wadhwani's solution sets second_high_sales only when two conditions are true:

          if (sales > second_high_sales)
          {
                if(temp != 0)

Tracing back, temp != 0 is true only if previously sales was > high_sales.  Thus, second_high_sales can only get a new value when high_sales gets a new value.

This misses a case where second_high_sales should be changed.  For example, consider the input sequence 2, 1.  After the program reads the 2, high_sales will be 2 and second_high_sales will be 0.  After it reads the 1, there is not a new high_sales value, and so neither value will change, while actually second_high_sales should be set to 1.

A new high is indeed one way to get a new second-high, but it is not the only way.  The other way is to read in a value that is lower than the high, but higher than the current second-high.  This was the idea of my fourth hint above.

jitendra_wadhwani's solution also retains the bug addressed by my second hint "When you demote a high to second-highest, don't forget to bring along the old high's count."  A concrete example may help.  If you have seen 67 occurrences of the high value 200 in the data, and then you read in a sales value of 210, 210 becomes the new high value and 200 becomes the second-highest value.  That should not cause you to discard the count of 67 occurrences of 200 already seen and start the count for 200 as second-highest over at 1. The count of 200s seen so far is still 67, so that should now be the count of occurrences of the second-highest values seen, which is stored in counter2.
Agreed Can rectify by following

Add
               else if(second_high_sales == 0 && sales != high_sales)
               {
                    second_high_sales = sales;
                    counter2 = 1;                
               }
with if(temp != 0)



while (infile >> id >> sales)
{
          cout << id << "      " << setw(8) << sales << endl;

          if (sales > high_sales)
          {
               temp = high_sales;
               high_sales = sales;
               counter = 0;
          }
          else
          {
            temp = 0;
          }

          if (sales == high_sales)
               counter++;
         
          if (sales > second_high_sales)
          {
                if(temp != 0)
                {
                  second_high_sales = temp;
                  counter2 = 1;
               }
               else if(second_high_sales == 0 && sales != high_sales) // else if Added Now
               {
                    second_high_sales = sales;
                    counter2 = 1;                
               }
          }
          else if (sales == second_high_sales)
          {
             counter2++;
          }
}


condition
second_high_sales == 0 is for that second_high_sales is not updated yet and
sales != high_sales is for that in case inputs are 2,2,2,2

highest value will be 2
second highest will be still 0...

Final code is

while (infile >> id >> sales)
{
          cout << id << "      " << setw(8) << sales << endl;

          if (sales > high_sales)
          {
               temp = high_sales;
               high_sales = sales;
               counter = 0;
          }
          else
          {
            temp = 0;
          }

          if (sales == high_sales)
               counter++;
         
          if (sales > second_high_sales)
          {
                if(temp != 0)
                {
                  second_high_sales = temp;
                  counter2 = 1;
               }
               else if(second_high_sales == 0 && sales != high_sales) // else if Added Now
               {
                    second_high_sales = sales;
                    counter2 = 1;                
               }
          }
          else if (sales == second_high_sales)
          {
             counter2++;
          }
}
Since the original question said

> I would like to know how to solve this problem though for future referance.

, here's another procedural suggestion:

Attack the problem in small steps.  Instead of trying to write a program that solves the whole problem the first time, sneak up on it step by step.  Test each increment and make sure it produces correct results before going on to the next step.

Suggested breakdown:

1.  Write a program that finds the highest number in the input.  Don't worry about the second-highest number or the counts.
2.  Change the program so it also finds the second-highest number.
3.  Change the program so it also finds the count for the highest number.
4.  Change the program so it also finds the count for the second-highest number.
Avatar of vlahomt

ASKER

I am still unable to figure out how to properly find the second high value and count it's occurances.
Please try this one....

while (infile >> id >> sales)
{
          cout << id << "      " << setw(8) << sales << endl;

          if (sales > high_sales)
          {
               temp = high_sales;
               high_sales = sales;
               counter = 0;
          }
          else
          {
            temp = 0;
          }

          if (sales == high_sales)
               counter++;
         
          if (sales > second_high_sales)
          {
                if(temp != 0)
                {
                  second_high_sales = temp;
                  counter2 = 1;
               }
               else if(second_high_sales == 0 && sales != high_sales) // else if Added Now
               {
                    second_high_sales = sales;
                    counter2 = 1;                
               }
          }
          else if (sales == second_high_sales)
          {
             counter2++;
          }
}


In case any issue ...or not able to understand anyline please point it out ....will clear it...
// Here high_sales, temp, second_high_sales and sales all are zero
// This will work for only positive values...

while (infile >> id >> sales)
{
          cout << id << "      " << setw(8) << sales << endl;

          // Here sales contains some value....
          // For first time remaining are zero and first time this condition will be true we need to store it as highest value
          // After first time if new value in sales in greater than previous high_sales
          // we need to update high_sales and reset teh second highest    sales value and counter
          if (sales > high_sales)
          {
               
               temp = high_sales; // Storing previous highest value to temp.
               high_sales = sales; // Storing new value as high sales.
               counter = 0; //Reseting counter to zero....count for this occurence will be updated below.
          }
          else
          {
            temp = 0; // Resetting temp value to zero otherwise it may contain previous highest value.
          }

         // if sales and counter are equal increasing the counter....
          if (sales == high_sales)
               counter++;
 
         //process for finding highest value and its counter is over
 
 
          // Now if sales is greater than second highest we need to doo something else if it is equal increase counter and if it is less ignore...
          if (sales > second_high_sales)
          {
                // Here sales > second_high_sales now two cases
                // if temp != 0 says that highes value is just updated and temp contains previous highest value so make it second highest
                 
                if(temp != 0)
                {
                  second_high_sales = temp; // Storing previous highest as second highest
                  counter2 = 1; //Setting the counter to 1 fit current occurence
               }
               // Now temp is now zero means highest value is not updated but sales > second_high_sales
               // Again we need to reset the second highest value and its counter
               // But with a check that is is not equal to high_sales
               // because if it is equal to high_sales we have increased the counter of high_sales and now it should be ignored
               else if(second_high_sales == 0 && sales != high_sales) // else if Added Now
               {
                    second_high_sales = sales; // Storing new valu as second highest
                    counter2 = 1;  //Setting the counter to 1 fit current occurence              
               }
          }
         // Now here sales is not greater than second_high_sales os if it is equal we have to increase counter else ignore
          else if (sales == second_high_sales)
          {
             counter2++;
          }
}

here, i try to give a pseudocode instead of the code to tackle the problem

setting up values
first = 0 //highest initially is 0
firstC=0 //highest count is 0
second =0 //second highest initially is 0
secondC =0 //second highest count is 0

while more input
  read input
  check input with first
  if input is > first
  {
    //demote first to second
    second = first
    secondC  = firstC
    //set input as first
    first = input
    firstC=1
  }
  else if input == first
  {
    ++firstC
  }
  else if input > second (but it would be less than first)
  {
    second = input
    secondC=1
  }
  else if input == second
  {
    ++secondC
  }
}

i din't have much time to read through the others code but i believe the did exactly what i explained here (but in code form). hope tt helps you to understand how to find the second highest
normally, when i have this sort of problem, i don't jump into the code directly. rather, work out the logic and pseudocode behind how to taclke them. ask youself, what happens if you have a certain number bigger than the first? equal to first? smaller than first? bigger than second?equal to second?smaller then second?
did you cover all cases?
ASKER CERTIFIED SOLUTION
Avatar of jitendra_wadhwani
jitendra_wadhwani

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of vlahomt

ASKER

This is an extra credit problem I have just been busy with required programs that I have not had a chance to revist this one yet.

thanks