How to find out how many students are enrolled in a certain class

I'm trying to make a program that generates 300 students, and for each student, they have 3-6 courses, with no duplicate classes, and for each course they have a midterm1, midterm2, final exam, and a total grade(m1+m2+final). So far I figured how to make sure each student has 3-6 courses w/no duplicate, but I'm having trouble on how to implement the class counter, which would tell me how many students enrolled in all the classes available.

I thought of while generating the 300 students, I would iterate through their bag, and if they had class 102, counter102 gets incremented, if they have class 104, counter104 gets incremented, and so on. But I'm having trouble translating that into code.

I thought of doing something like this in student.cpp:

for (m_course.begin(); m_course.end(); m_course++){
if (m_course.get() = class 102){
counter102++;
}
}

and then another function which returned if class102[0] = 1;

but it just got really complicated, and i'm not sure if theres an easier way


This is what I have so far:

Bag2.h (cant change this file):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
using namespace std;

template <class T>
class Bag
{
    public:
        // TYPEDEFS and MEMBER CONSTANTS
        typedef T value_type;
        typedef std::size_t size_type;
        static const size_type DEFAULT_CAPACITY = 30;

        // CONSTRUCTORS and DESTRUCTOR
        Bag(size_type initial_capacity = DEFAULT_CAPACITY);
        Bag(const Bag& source);
        void operator =(const Bag& source);
        ~Bag() { delete [] data; }

        // MODIFICATION MEMBER FUNCTIONS
        void reserve(size_type new_capacity);
        bool erase_one(const value_type& target);
        size_type erase(const value_type& target);
        void insert(const value_type& entry);
        void operator +=(const Bag& addend);

        // CONSTANT MEMBER FUNCTIONS
        size_type size( ) const { return used; }
        size_type count(const value_type& target) const;

        // SIMPLE ITERATOR
        void begin() { current = 0; }
        bool end() const { return current >= used; }
        int operator++(int) { assert(!end()); current++; }
        T& get() { assert(!end()); return data[current]; }

    private:
        value_type *data;     // Pointer to partially filled dynamic array
        size_type used;       // How much of array is being used
        size_type capacity;   // Current capacity of the Bag
        size_type current;    // Iterator's current position.
};




// NONMEMBER FUNCTIONS for the Bag class
template <class T>
Bag<T> operator +(const Bag<T>& b1, const Bag<T>& b2);

///////////// Template Conversion begins here?

template <class T>
const typename Bag<T>::size_type Bag<T>::DEFAULT_CAPACITY;

template <class T>
Bag<T>:: Bag(size_type initial_capacity)
{
  data = new T[initial_capacity];
  capacity = initial_capacity;
  used = 0;
}

template <class T>
Bag<T>::Bag(const Bag<T>& source)
  // Library facilities used: algorithm
{
  data = new T[source.capacity];
  capacity = source.capacity;
  used = source.used;
  copy(source.data, source.data + used, data);
}

template <class T>
void Bag<T>::reserve(size_type new_capacity)
  // Library facilities used: algorithm
{
  value_type *larger_array;
  if (new_capacity == capacity)
    return; // The allocated memory is already the right size.
  if (new_capacity < used)
    new_capacity = used; // Canêt allocate less than we are using.
  larger_array = new value_type[new_capacity];
  copy(data, data + used, larger_array);
  delete [ ] data;
  data = larger_array;
  capacity = new_capacity;
}

template <class T>
typename Bag<T>::size_type Bag<T>::erase(const value_type& target)
{
  size_type index = 0;
  size_type many_removed = 0;
  while (index < used) {
    if (data[index] == target) {
      --used;
      data[index] = data[used];
      ++many_removed;
    }
    else ++index;
  }
  return many_removed;
}

template <class T>
bool Bag<T>::erase_one(const value_type& target)
{
  size_type index; // The location of target in the data array
  // First, set index to the location of target in the data array,
  // which could be as small as 0 or as large as used-1.
  // If target is not in the array, then index will be set equal to used.
  index = 0;
  while ((index < used) && (data[index] != target))
    ++index;
  if (index == used) // target isn't in the Bag, so no work to do
    return false;
  // When execution reaches here, target is in the Bag at data[index].
  // So, reduce used by 1 and copy the last item onto data[index].
  --used;
  data[index] = data[used];
  return true;
}

template <class T>
void Bag<T>::insert(const value_type& entry)
{
  if (used == capacity) reserve(used+1);
  data[used] = entry;
  ++used;
}

template <class T>
void Bag<T>::operator +=(const Bag<T>& addend)
  // Library facilities used: algorithm
{
  if (used + addend.used > capacity)
    reserve(used + addend.used);
  copy(addend.data, addend.data + addend.used, data + used);
  used += addend.used;
}

template <class T>
void Bag<T>::operator =(const Bag<T>& source)
  // Library facilities used: algorithm
{
  value_type *new_data;
  // Check for possible self-assignment:
  if (this == &source) return;
  // If needed, allocate an array with a different size:
  if (capacity != source.capacity) {
    new_data = new value_type[source.capacity];
    delete [ ] data;
    data = new_data;
    capacity = source.capacity;
  }
  // Copy the data from the source array:
  used = source.used;
  copy(source.data, source.data + used, data);
}

template <class T>
typename Bag<T>::size_type Bag<T>::count(const value_type& target) const
{
  size_type answer;
  size_type i;
  answer = 0;
  for (i = 0; i < used; ++i)
    if (target == data[i]) ++answer;
  return answer;
}

template <class T>
Bag<T> operator +(const Bag<T>& b1, const Bag<T>& b2)
{
  Bag<T> answer(b1.size( ) + b2.size( ));
  answer += b1;
  answer += b2;
  return answer;
}


Student.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
class Course{
    public:
        Course();
        int RandomInt(int Lowest, int Highest);
        void pick_class();
        int generate_m1();
        int generate_m2();
        int generate_fexam();
        void calculate_total();
        int get_m1();
        int get_m2();
        int get_fexam();
        int get_total();
        friend ostream& operator<<(ostream& os, const Course& course);
        friend bool operator==(const Course& coursea,  const Course& courseb);
    private:
        int enrolled_class[1];
        int m1[1];
        int m2[1];
        int fexam[1];
        int total[1];


};

class Student{
    public:
        Student();
        void inclass();
        //int class_count();
        void generate_fname(); void generate_lname(); void generate_ssid();
        friend ostream& operator<<(ostream& os, const Student& student);


    private:

        string fname[1];
        string lname[1];
        mt19937 m_mt;
        string ssid[1];
        Bag<Course> m_course;
};



Last edited on
Student.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include <iostream>
#include <random>
#include <string>
#include <functional>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <cstdlib>  // Provides size_t
#include <cassert>
#include <cstring>
#include <string>
#include "Student.h"
#include "BM.h"

using namespace std;


//ctors


Student::Student()
{
    generate_fname(); //each student has a fname
    generate_lname(); //each student has a lname
    generate_ssid(); //each student has an SSID
    //each student has 3-6 courses inserted into a bag
    int j = (rand() % (7-3) + 3);
    m_course.reserve(j);
    for (int i=0; i<j; i++)
    {
        Course c = Course();
        if(m_course.count(c)>0)
        {
          i--; // if course is already in bag, repeat the step
        }
        else //if course is not in bag, insert it@
        {
          m_course.insert(c);
        }

}
}

Course::Course()
{

    pick_class();
    calculate_total();

}






void Course::pick_class()
{
    int class_list[22] = { 102, 104, 204, 210, 212, 217, 220, 221, 301, 304, 317, 318, 322, 332, 335, 340, 412, 420, 450, 470, 480, 599 };
    enrolled_class[0] = class_list[RandomInt(0,21)];
}

void Course::calculate_total()
{
    m1[0] = generate_m1();
    m2[0] = generate_m2();
    fexam[0] = generate_fexam();
    total[0] = m1[0] + m2[0] + fexam[0];
}



int Course::RandomInt(int Lowest, int Highest)
{
    return (rand() % (Highest-Lowest) + Lowest);
}


void Student::inclass()
{

    for ( m_course.begin(); !m_course.end(); m_course++)
    {
        cout << m_course.get() << " ";
        }
}





//getters ////////////////
int Course::get_m1(){
    return m1[0];}
int Course::get_m2(){
    return m2[0];}
int Course::get_fexam(){
    return fexam[0];}
int Course::get_total(){
    return total[0];}


//generate info ///////////////////
int Course::generate_m1(){
    return box_muller(60,12);

}
int Course::generate_m2(){
    return box_muller(55,13);

}
int Course::generate_fexam(){
    return box_muller(46,14);

}

void Student::generate_fname(){
    int n = 1+(rand()%12);
    string MyNameString;
    int k = (rand()%26);
    char c = (char) (k+65);
    MyNameString += c;
    for(int i=0; i<n; i++){
        int k = (rand()%26);
        char c = (char) (k+97);
        MyNameString += c;
    }
    fname[0] = MyNameString;
}

void Student::generate_lname(){
    int n = 1+(rand()%12);
    string MyNameString;
    int k = (rand()%26);
    char c = (char) (k+65);
    MyNameString += c;
    for(int i=0; i<n; i++){
        int k = (rand()%26);
        char c = (char) (k+97);
        MyNameString += c;
    }
    lname[0] = MyNameString;}

void Student::generate_ssid(){

    random_device m_mt;
    uniform_int_distribution<int> dist(0,999999999);
    int n = dist(m_mt);
    string result;
    stringstream convert_int_to_string;
    convert_int_to_string << setw(9) << setfill('0') << n;
    result = convert_int_to_string.str();
    result.insert(3,1,'-');
    result.insert(6,1,'-');
    ssid[0] = result;
}


ostream& operator<<(ostream&outs, const Course &source){


      outs << source.enrolled_class[0] << " ";
    return outs;
}


bool operator==(const Course& ac, const Course& bc)
{
    if (ac.enrolled_class[0] == bc.enrolled_class[0])
        return true;
    else
        return false;
}


main.cpp:

1
2
3
4
5
6
7

int main(){
    for(int i=0; i<300; i++) // generate 300 students
    {
        Student studi; // each student has a bag of courses that contains 3-6 classes, with a m1,m2,final exam, and total grade for each class
    }
}
Last edited on
I thought of doing something like this in student.cpp:
1
2
3
class Student{
...
        Bag<Course> m_course;

for (m_course.begin(); m_course.end(); m_course++){
if (m_course.get() = class 102){
counter102++;
}
}
. . .
Bag2.h (cant change this file):

When you say you can’t change “Bag2.h”, do you also mean you must use it?
If your “m_course” must be a “Bag”, there’re things you can’t do. Have a look at its code:
void begin() { current = 0; }
Bag::begin() doesn’t return anything, so you can initialise nothing with it.

Moreover, class Bag doesn’t seem to implement any functionality to access its elements, like operator[] or method at(). It looks pretty limited, from my point of view.

Anyway, in your code there a few things I’d give a second look at:
1) Class Course:
1
2
3
4
5
int enrolled_class[1];
int m1[1];
int m2[1];
int fexam[1];
int total[1];


Class Student:
1
2
3
string fname[1];
string lname[1];
string ssid[1];

What’s the point of having a single element array? Actually, looking at the rest of your code, it seems ‘simple’ ints and std::strings would fit with what you try to do.

2) You declare “m_mt” as a std::mt19937 in class Student, but you never use it, and then you hide it in Student::generate_ssid(). Anyway, throughout the code you use mainly the C rand() feature. I think that just makes the code unclear.

3) What’s there in BM.h?

4) Are you keeping both class Course and class Student in Student.h? And their implementations both in Student.cpp? Are you really mixing up their method definitions in random order?

5) In main() you declare 3 hundreds times the same object, which is destroyed at the end of every iteration.

6) Where do you define “box_muller”?

7) The implementation of
friend ostream& operator<<(ostream& os, const Student& student);
is missing.

8) I’d shorten this code:
1
2
3
4
5
6
7
8
9
10
11
12
for (int i=0; i<j; i++)
{
    Course c = Course();
    if(m_course.count(c)>0)
    {
      i--; // if course is already in bag, repeat the step
    }
    else //if course is not in bag, insert it@
    {
      m_course.insert(c);
    }
}

This way:
1
2
3
4
5
for (int i=0; i<j; /**/)
{
    Course c = Course();
    if(m_course.count(c) == 0) { m_course.insert(c); ++i; }
}

Because I think it’s easier to read.

Is this an assignment?
First things first -- get it to compile. Had to make a few changes so that the streams were friendly enough.

Bag's iterator is commented as "simple" but this really means that it's "simple" to implement but more difficult and counter-intuitive to use. The Bag<Course>, e.g. "courses_", cant be const, because in order to iterate you need to modify the Bag ( courses_++ ). I personally think it would've been worth the extra effort to write a real iterator.

Anyways, working/compiling project is here (files on the left): https://repl.it/repls/SecretDrySpreadsheets

I might've taken the liberty to mark the private variables with underscores ;D Also, I believe m1() { return m1_; } is more stylistic for C++ than prefixing the getter with "get" -- the latter is a Java thing iirc.

Side note: technically, your random course selection works, but with limited number of courses it could in theory take a long time to choose 6 unique ones (if RNG was bad and kept hitting an index already chosen). I did a brief google for C++ versions of N choose K, and possible selection for arrays, but those implementations are not trivial. I wonder if it makes any sense to do it as follows:
1. Make integer array "arr" representing all possible indices in CLASS_LIST. This is purposefully its own, new array to not change the original class list order.
2. Shuffle arr.
3. Select the first K elements of arr, and use these as indices for CLASS_LIST

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <array>
#include <algorithm>
#include <random>

using namespace std;

const static int CLASS_SIZE = 22;
int CLASS_LIST[CLASS_SIZE] = { 
    102, 104, 204, 210, 212, 217, 220, 221, 301, 304, 317,
    318, 322, 332, 335, 340, 412, 420, 450, 470, 480, 599 };
random_device rd;
mt19937 mt(rd());

// n choose k with shuffling
void ClassCombination(int k)
{
    if (k>CLASS_SIZE) return;
    array<int,CLASS_SIZE> arr;
    iota(arr.begin(), arr.end(), 0);
    shuffle(arr.begin(), arr.end(), mt);

    for (int i=0; i<k; ++i)
        cout << CLASS_LIST[arr[i]] << " ";
    cout << endl;
}

int main() 
{
    int k;
    for (int x=1; x<=10; ++x)
    {
        k = rd()%4 + 3;  // From 3 to 6
        ClassCombination(k);
    }
    return 0;
}

can test this at https://repl.it/repls/GoldMagentaTechnology
332 470 480 450 
301 322 420 102 104 
420 204 304 317 104 332 
301 340 412 
317 599 318 
204 221 335 420 322 
340 217 599 
204 104 317 220 217 340 
332 599 412 221 317 104 
599 340 318 104 
Last edited on
Topic archived. No new replies allowed.