Okay, I was given this problem, its another of those file I/O streams and I was wondering how I can change this code to be more "efficient" and change a lot of things. I'm having trouble on what I should change and what I should keep. Please help me out on this one. Thank you! Oh, this code does work by the way. Please nothing too fancy! I would just like to change a lot of things to make it better.

       Write a program that reads in a set of positive integers, representing test
       scores for a class, and outputs how many times a particular number appears in the list.
       You may assume that the data set has, at most, 100 numbers and that -999 marks the end
       of the input data. The numbers must be output in increasing order. For example, for the
       data:
       55 80 78 92 95 55 78 53 92 65 78 95 85 92 85 95 95
       the output is:

                            Test Score  Count
                                53        1
                                55        2
                                65        1
                                78        3
                                80        1
                                85        2 
                                92        3
                                95        4

            input2.txt has this numbers: 55 80 78 92 95 55 78 53 92 65 78 95 85 92 85 95 95



#include <iostream>//include statement(s)
#include <iomanip>
#include <fstream>

using namespace std;//using namespace statement(s)

const int MAX_SIZE = 999;//constant variable declaration(s)

void getScoresAndSize(int arry[], int& arrySize);//void function header(s)
void displayScoreArray(int arry[], int arrySize);
void orderArray(int arry[], int arry2[], int arrySize);
void outputData(int arry[], int arrySize);

int main()
{
    int scoreArray[MAX_SIZE];//variable declaration(s)
    int newScoreArray[MAX_SIZE];
    int ArraySize;  

    getScoresAndSize(scoreArray, ArraySize);//void function call(s)

    displayScoreArray(scoreArray, ArraySize);

    orderArray(scoreArray, newScoreArray, ArraySize);

    cout << "After reordering the array, ";
    displayScoreArray(newScoreArray, ArraySize);
    outputData(newScoreArray, ArraySize);
    cout << "Program is exiting..." << endl;

    system ("PAUSE");//Black box to appear and stay
    return 0;//return statement(s)
}

void getScoresAndSize(int arry[], int& arrySize)
{
    ifstream scorFil;
    scorFil.open("input2.txt");

    if (scorFil.fail())//if score file fails, program outputs "cannot open file"
    {
        cout << "The input2.txt file was not opened by the program. Ending program..." << endl;
        exit(1);
    }
    else if (!scorFil.fail())//if score file opens, program outputs "file was opened successfully"
        cout << "The input2.txt file was succesfully opened by the program." << endl;

    int score;
    arrySize = 1;

    for(int i = 0; !scorFil.eof(); i++ && arrySize++)//for loop for the readable file, collect the scores
    {                                                //the array size is incremented as well
        scorFil >> score;
        arry[i] = score;
    }
    cout << "The scores from the file were succesfully transferred into an array."<<endl;
    cout << "The array contains " << arrySize << " scores." << endl << endl;
    scorFil.close();

    return;
}

void displayScoreArray(int arry[], int arrySize)
{
    cout << "The Scores are: " << endl;
    for (int i = 0; i <= (arrySize - 1); i++)//for loop to print out each score
    {
        cout << arry[i] << " ";//spaces between each score

        if ((i + 1) % 21 == 0)
            cout << endl;
    }

    cout << endl;
    cout << endl;

    return;
}

void orderArray(int arry[], int arry2[], int arrySize)
{
    int index = 0;//new array for index

    for (int score = 0; score <= 100; score++)//for loop to check the scores from 0 to 100
    {
        for (int i = 0; i <= (arrySize - 1); i++)
        {
            if(arry[i] == score)
            {
                arry2[index] = score;
                index++;//index increments
            }
        }
    }
}

void outputData(int arry[], int arrySize)
{
    int oldNum = arry[0];
    int count = 1;
    cout << "Score" << setw(11) << "Count" << endl;//output header

    for(int i = 1; i <= arrySize; i++) 
    {
        if(arry[i] == oldNum)
        {
            count++;//counter increments
        }

        else
        {
            cout << " " << oldNum << setw(11) << count << endl;
            count = 1;
        }

        oldNum = arry[i];
    }

    cout << endl;
}

Thanks for the help!

One thing, I would change the collection to a map instead of an array, the score as the key and the number of times it appears is the value. This way, the elements are sorted when you read them from the file. This gives you the option of calling the Size() function to get the size instead of counting the elements separately. Also the Find function can be used to get the number of times a score is repeated. All this can be accomplished in one function. Then it's a simple matter to iterate through the map collection and print out the data.

Also using eof as the limit of your loop is unsafe, it's better to use the return from the actual file access while(scorFil >> score).

Edited 2 Years Ago by tinstaafl

Can you show me how to do this? I'm sorta confused

arrySize = 1;

for(int i = 0; !scorFil.eof(); i++ && arrySize++)//for loop for the readable file, collect the scores
{                                                //the array size is incremented as well
    scorFil >> score;
    arry[i] = score;
}

Becomes

arrySize = 0;
int i = 0;
while(scorFil >> score)
{
    arry[i++] = score;
    arrySize++;
}

Oh okay, I fixed this problem, but I wanna add in a function or two to this code. OR maybe remove a function or two and add it into another function.

This is what I have so far:

#include <iostream>//include statement(s)
#include <iomanip>
#include <fstream>

using namespace std;//using namespace statement(s)

const int MAX_SIZE = 999;//constant variable declaration(s)

void getScoresAndSize(int arry[], int& arrySize);//void function header(s)
void displayScoreArray(int arry[], int arrySize);
void orderArray(int arry[], int arry2[], int arrySize);
void outputData(int arry[], int arrySize);

int main()
{
    int scoreArray[MAX_SIZE];//variable declaration(s)
    int newScoreArray[MAX_SIZE];
    int ArraySize;  

    getScoresAndSize(scoreArray, ArraySize);//void function call(s)

    displayScoreArray(scoreArray, ArraySize);

    orderArray(scoreArray, newScoreArray, ArraySize);

    cout << "After reordering the array, ";
    displayScoreArray(newScoreArray, ArraySize);
    outputData(newScoreArray, ArraySize);

    system ("PAUSE");//Black box to appear and stay
    return 0;//return statement(s)
}

void getScoresAndSize(int arry[], int& arrySize)
{
    ifstream scorFil;
    scorFil.open("input2.txt");

    if (scorFil.fail())//if score file fails, program outputs "cannot open file"
    {
        cout << "The input2.txt file was not opened by the program. Ending program..." << endl;
        exit(1);
    }
    else if (!scorFil.fail())//if score file opens, program outputs "file was opened successfully"
        cout << "The input2.txt file was succesfully opened by the program." << endl;

    int score;
    arrySize = 0;
    int i = 0;
    while(scorFil >> score)
    {
        arry[i++] = score;
        arrySize++;
    }
    cout << "The scores from the file were succesfully transferred into an array."<<endl;
    cout << "The array contains " << arrySize << " scores." << endl << endl;
    scorFil.close();

    return;
}

void displayScoreArray(int arry[], int arrySize)
{
    cout << "The Scores are: " << endl;
    for (int i = 0; i <= (arrySize - 1); i++)//for loop to print out each score
    {
        cout << arry[i] << " ";//spaces between each score

        if ((i + 1) % 21 == 0)
            cout << endl;
    }

    cout << endl;
    cout << endl;

    return;
}

void orderArray(int arry[], int arry2[], int arrySize)
{
    int index = 0;//new array for index

    for (int score = 0; score <= 100; score++)//for loop to check the scores from 0 to 100
    {
        for (int i = 0; i <= (arrySize - 1); i++)
        {
            if(arry[i] == score)
            {
                arry2[index] = score;
                index++;//index increments
            }
        }
    }
}

void outputData(int arry[], int arrySize)
{
    int oldNum = arry[0];
    int count = 1;
    cout << "Score" << setw(11) << "Count" << endl;//output header

    for(int i = 1; i <= arrySize; i++) 
    {
        if(arry[i] == oldNum)
        {
            count++;//counter increments
        }

        else
        {
            cout << " " << oldNum << setw(11) << count << endl;
            count = 1;
        }

        oldNum = arry[i];
    }

    cout << endl;
}

Here's an example using a map that reads the file, adds the scores, and counts how many times each score is present:

    #include <iostream>
    #include <fstream>
    #include <map>
    #include <utility>

    using namespace std;



    int main(int argc, char* argv[])
    {
        ifstream file;
        file.open(argv[1]);
        map<int, int> scores;
        int temp;
        while (file >> temp)
        {
             //This will be a pair, either, an iterator to the new element and a 
             //boolean set to true, or an iterator to an existing element and a 
             //boolean set to false.
            auto nextelement = scores.emplace(temp, 1);
            if (!nextelement.second)
            {
                auto pr = *nextelement.first;
                scores[pr.first]++;
            }
        }
        for (pair<int, int> pr : scores)
            cout << pr.first << '\t' << pr.second << '\n';
        return 0;
    }

Some of this code uses c++11 if your compiler/IDE isn't updated for this you may have to change some of the code.

Edited 2 Years Ago by tinstaafl

That's a nice code! The problem is that, for this assignment we can't use pointers :( BUT! I have actually just learned pointers and I haven't started on the assignment with pointers yet...but I will get to that tomorrow though :) lol. But for now, I just want to know if there is a "cleaner" way to make it look better.

The way I would do it without using the stl would be like this

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    ifstream fin("data.txt");
    int scroes[101];

    // make all scores 0
    for (int i = 0; i < 101; i++)
        scores[i] = 0;

    // read file and fill array
    int temp;
    while (fin >> temp)
        scores[temp]++;

    // display
    for (int i = 0; i < 101; i++)
        if (scores[i] > 0)
            cout << i << "\t" << scores[i];
}

If you need to output to contents of the file at then end then you would need a second array and you would put each score into that array inside the while loop.

Here's an example without pointers. It does the same thing but uses a vector<pair<int,int>>. It also requires a couple of helper functions and using the sort function from the <algorithm> header:

#include <iostream>
#include <fstream>
#include <vector>
#include <utility>
#include <algorithm>

using namespace std;

int FindKey(vector<pair<int, int>> input, pair<int, int> pr)
{
    int size = input.size();
    int i = 0;
    for (; i < size;i++)
    {
        if (pr.first == input[i].first)
            return i;
    }
    return -1;
}
bool CompareKeys(pair<int, int> a, pair<int, int> b)
{
    return a.first < b.first;
}
int main(int argc, char* argv[])
{
    ifstream file;
    file.open(argv[1]);
    vector<pair<int, int>> scores;
    int temp;
    while (file >> temp)
    {
        pair<int,int> pr(temp, 1);
        int index = FindKey(scores, pr);
        if (index == -1)
        {
            scores.emplace_back(pr);
        }
        else
            scores[index].second++;
    }
    sort(scores.begin(), scores.end(), CompareKeys);
    for (pair<int, int> pr : scores)
        cout << pr.first << '\t' << pr.second << '\n';
    return 0;
}

Edited 2 Years Ago by tinstaafl

This example may be closer to what would be expected of just a 'beginning student:

1 -> NO STL used
2 -> Simple bubble sort used
3 -> Only tricky part ... counting / outputing ALL repeats

// scores_counts.cpp //

/*
    Write a program that reads in a set of positive integers,
    representing test scores for a class, and outputs how
    many times a particular number appears in the list.
    You may assume that the data set has, at most, 100
    numbers and that -999 marks the end of the input data.

    The numbers must be output in increasing order.

    For example, with this input data in file 'input2.txt':
    55 80 78 92 95 55 78 53 92 65 78 95 85 92 85 95 95 -999

    the output is:

    File 'input2.txt' holds these 17 scores:
    55 80 78 92 95 55 78 53 92 65 78 95 85 92 85 95 95

    Or ... showing scores sorted in ascending order:
    53 55 55 65 78 78 78 80 85 85 92 92 92 95 95 95 95

    SCORE      FREQUENCY
    53         1
    55         2
    65         1
    78         3
    80         1
    85         2
    92         3
    95         4

    For bonus ... display a bar-graph of the distribution ...

*/

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>

using namespace std;

const string FNAME = "input2.txt";
const int MAX_ARY_SIZE = 100;


int loadAryFromFile( int ary[], int max_size, const string& filename );
void print( const int ary[], int size );
void bubble_sort( int ary[], int size );

void countShowScoreRepeats( const int ary[], int size );
void showBarGraph( const int ary[], int size );



int main()
{
    int ary[MAX_ARY_SIZE];
    int size = loadAryFromFile( ary, MAX_ARY_SIZE, FNAME );

    if( size )
    {
        cout << "\nFile '" << FNAME << "' holds these "
             << size << " scores:\n";
        print( ary, size );


        bubble_sort( ary, size );
        cout << "\n\nOr ... showing scores sorted in "
             << "ascending order:\n";
        print( ary, size );

        cout << "\n\nSCORE \tFREQUENCY \n";
        countShowScoreRepeats( ary, size );

        cout << "\nShowing BAR GRAPH of SCORES ... \n";
        showBarGraph( ary, size );
    }

    cout << "\nPress 'Enter' to continue/exit ... " << flush;
    cin.get();
}



int loadAryFromFile( int ary[], int max_size, const string& filename )
{
    int size = 0;
    ifstream fin( filename.c_str() );
    if( fin )
    {
        int tmp;
        while( size < max_size && fin >> tmp && tmp != -999 )
        {
            ary[size] = tmp;
            ++size;
        }
        if( size == max_size )
            cout << "\nYou reached the max array size here of "
                 << max_size << endl;
        else if( !fin )
             cout << "\nYou have read the file "
                  << filename
                  << "\nbut no -999 was found at the end.\n";
        else // all ok ...
        {
            ;
            /*
            cout << "\nYou have reached the end of file flag"
                 << "\nvalue of -999 for file: "
                 << filename << endl;
            */
        }


        // fin.close(); // not really needed here, why ?
    }
    else
        cout << "\nThere was a problem opening file: "
             << filename << endl;
    return size;
}

void print( const int ary[], int size )
{
     for( int i = 0; i < size; ++ i )
     {
         cout << ary[i] << ' ';
     }
}

void bubble_sort( int ary[], int size )
{
    bool swap;
    do
    {
        swap = false;
        for( int i = 1; i < size; ++ i )
        {
            if( ary[i-1] > ary[i] )
            {
                int tmp = ary[i-1];
                ary[i-1] = ary[i];
                ary[i] = tmp;
                swap = true;
            }
        }
        --size;
    }
    while( swap ) ;
}


void countShowScoreRepeats( const int ary[], int size )
{
    int i = 0, j = 1, repeats = 0;
    if( size > 1 )
        while( j < size )
        {
            if( ary[i] == ary[j] )
            {
                ++repeats;
                ++j;
                if( j == size )
                    cout << ary[i] << "\t" << repeats+1
                         << endl;
            }
            else
            {
                cout << ary[i] << "\t" << repeats+1
                     << endl;
                repeats =  0;
                i = j;
                ++j;
            }
        }
    else if( size == 1 )
        cout << ary[0] << "\t" << 1 << endl;
}

void showBarGraph( const int ary[], int size )
{
    int count = 0, j = 0, low = 0, high = 5, total = 0;

    bool show = false;
    while( j < size )
    {
        while( j < size && ary[j] <= high )
        {
            ++count;
            ++j;
        }

        // do not show leading 'empty' (score) 'slots' ...
        if( count ) show = true;

        if( show )
            cout << setw(3) << low << " to "
                 << setw(3) << high << " :"
                 << string( count, '*' ) << endl;

        total += count;
        count =  0;

        low = high+1;
        high += 5;
    }

    cout << "\nTotal number of scores: " << total << endl;
}

Edited 2 Years Ago by David W

If simpler is needed you can use a 2 dimensional array. Here's some code that reads the file, stores the scores, computes the repeats in one routine, then sorts the data, using a QuickSort routine, by score, then displays the formatted data:

#include <iostream>
#include <fstream>

using namespace std;

const int SIZE = 100;
const int LAST_ELEMENT = -999;
int scores[100][2];
void SortByKey(int arr[][2], int right, int left = 0) {
    int i = left, j = right;
    int pivot = arr[(right + left) / 2][0];
    while (i <= j) {
        while (arr[i][0] < pivot)
            i++;
        while (arr[j][0] > pivot)
            j--;
        if (i <= j) {
            int tmp[2];
            tmp[0] = arr[i][0];
            tmp[1] = arr[i][1];
            arr[i][0]= arr[j][0];
            arr[i][1] = arr[j][1];
            arr[j][0] = tmp[0];
            arr[j][1] = tmp[1];
            i++;
            j--;
        }
    };
    if (left < j)
        SortByKey(arr, j, left);
    if (i < right)
        SortByKey(arr, right, i);
}
int FindKey(int input[][2], int key)
{
    int i = 0;
    for (; i < SIZE && input[i][0] != 0; i++)
    {
        if (key == input[i][0])
            break;
    }
    return i;
}
void InitArray(int input[][2])
{
    for (int i = 0; i < SIZE; i++)
    {
        input[i][0] = 0;
        input[i][1] = 0;
    }
}

int main(int argc, char* argv[])
{
    ifstream file;
    file.open(argv[1]);
    InitArray(scores);
    int temp;
    while (file >> temp)
    {
        int value = 1;
        int index = FindKey(scores, temp);
        if (scores[index][0] == 0)
        {
            scores[index][0] = temp;
        }

        scores[index][1]++;
    }
    int limit = FindKey(scores, LAST_ELEMENT);
    SortByKey(scores, limit - 1);
    for (int i = 0; i < limit; i++)
        cout << scores[i][0] << '\t' << scores[i][1] << '\n';
    return 0;
}

Edited 2 Years Ago by tinstaafl

The OP wanted to be able to print out the original scores that were in the file ... so these would need to be printed out as they were read from file in the above example by "tinstaafl"

Quick sort is an appropriately fast sort for large arrays, but often is 'over-kill' for small ... especially for beginner coders.

Rather than use a 2-D array (added complexity?)... using a 1-D array of struct ... may be simpler to understand and code for beginner coders?

struct ScoresFreq
{
   int score;
   int freq; // frequency of score

   ScoresFreq() : score(0), freq(0) {}
} ;

But if the scores are all in the range of 0..100

just using an array of 101 int's ...

all initaled to 0

may be the simplest beginner approach?

Just update the array for each score read from file:
(while also printing out that score)

++ array[score] ; // score is in range 0..100 //

Then ... just print out the array ...
skipping over the 'zero entries'
to get a printout of scores and frequencies
in order of increasing score value

@R_R_A please note: the above post was not meant to in anyway discourage you from studying the very useful code example by @tinstaafl

You will do well to study his skillfully designed code examples regularly provided here ... at our Dani's wonderful coding forum :)

'Quick Sort' is a method that you will want to know if you go beyond just the 'beginnings' ... or if you need to sort data sets of more than just a few elements, (unless those data sets are already sorted, i.e. all sorted, except for maybe an element or two.)

Also handling 2D arrays (or multi-D arrays) is a skill to acquire if you wish to go beyond the 'beginnings' ...

Anyways, take a look at the added comments here ...

and the code // commented out

and the edits / changes ...

These may make that example code simpler to run
and for you to follow ...

You can run this from the command line or a batch file as per the following batch file example:

@echo off

rem fileName: run_2dExample.bat

2dExample input2.txt
pause

Ok ... take a look at this code again, if you like ...

// 2dExample.cpp //  // this version: 2014-07-02 //

// revised from C++ code posted 2014-07-01 at ...
// http://www.daniweb.com/software-development/cpp/threads/480984/write-a-program-that-reads-in-a-set-of-positive-integers-representing-test
// Original code by DANI'S 'tinstaafl' expert coder ... //



#include <iostream>
#include <fstream>

#include <cstring> // re. memcpy

using namespace std;

const int MAX_SIZE = 100;
const int LAST_ELEMENT = -999; // 'flag' value for 'endOfFile'

// defaults to start at index 0 to 'right' index ... //
void quick_sort( int arr[][2], int right, int left = 0 )
{
    int i = left, j = right;
    // take 'mid' score value here ... as pivotVal //
    int pivotVal = arr[(right + left) / 2][0];
    while( i <= j )
    {
        while( arr[i][0] < pivotVal ) ++i;
        while (arr[j][0] > pivotVal ) --j;
        if( i <= j ) // swap //
        {
            int tmp[2];
            memcpy( &tmp, &arr[i], sizeof tmp );
            memcpy( &arr[i], &arr[j], sizeof tmp  );
            memcpy( &arr[j], &tmp, sizeof tmp  );

            /*
            tmp[0] = arr[i][0];
            tmp[1] = arr[i][1];
            arr[i][0]= arr[j][0];
            arr[i][1] = arr[j][1];
            arr[j][0] = tmp[0];
            arr[j][1] = tmp[1];
            */
            ++i;
            --j;
        }
    };

    // Note: here are the recursive calls ...
    if( left < j  ) quick_sort( arr, j,  left );
    if( i < right ) quick_sort( arr, right, i )  ;
}

// returns 'size' if not found ... //
int findKey( int input[][2], int size, int key )
{
    int i = 0;
    for( ; i < size /* && input[i][0] != 0*/ ; ++i )
    {
        if( key == input[i][0] )
            break;
    }
    return i;
}

// redundant with this revised method //
/*
void initArray( int input[][2], int size )
{
    for( int i = 0; i < size; ++i )
    {
        input[i][0] = 0;
        input[i][1] = 0;
    }
}
*/


int main( int argc, char* argv[] )
{
    if( argc > 1 )
    {
        ifstream file( argv[1] ) ;
        if( file )
        {
            // print file name in preparation to show scores //
            cout << "'" << argv[1] << "' :";

            // get memory to hold 'MAX_SIZE' scores and counts //
            int scores[MAX_SIZE][2]; 

            //initArray( scores, MAX_SIZE ) ;

            int tmp,
                size = 0; // for 'keeping track' of array size
            while( size < MAX_SIZE && file >> tmp && tmp != -999 )
            {
                cout << ' ' << tmp; // print as being read //

                // int value = 1; // variable not used here //
                int index = findKey( scores, size, tmp );

                //if( scores[index][0] == 0 )
                if( index == size ) // if not found, then add to end //
                {
                    scores[size][0] = tmp;
                    scores[size][1] = 1; // 1st time for this score //
                    ++size;
                }
                else
                    ++ scores[index][1]; // increment this score count //

            }
            cout << endl;

            //int limit = findKey( scores, size, LAST_ELEMENT );

            quick_sort( scores, size-1 /*limit - 1 */ );

            cout << "\nSCORES\tFREQUENCIES\n";
            for( int i = 0; i < size /* limit */ ; ++i )
                cout << scores[i][0] << '\t' << scores[i][1] << '\n';
        }
        else
            cerr << "\nThere was a problem opening file "
                 << argv[1] << endl;
    }
    else
        cerr << "argc = " << argc
             << "\n\nExpecting argc = 2 \n(Usage: command line"
             << " or batch file, as per the following):\n"
             << "\nprogramName.exe scoresFileName.txt"
             << endl;
    return 0;
}

Edited 2 Years Ago by David W

This article has been dead for over six months. Start a new discussion instead.