This is Part 6 of the 7-part Exercise 6-0. Click here to see the other parts.
Exercise 6-0 (Part 6 / 7)
Relating to section 6.3.1 of the textbook (page 117-118). Implement and test out the “two-pass extract_fails” program. This program essentially split the students into two groups – failed and passed students. This version of extract_fails function uses remove_copy_if and erase from the <algorithm> directive. (Note that the original version of extract_fails function was first introduced in Chapter 5 / my Solution to Exercise 5-0.)
The Project
This section summarises the partitioned program in the form of C++ source and header files.
Source File List
Header File List
Source Files
main.cpp
#include <iostream> // std::cin, std::cout, std::endl #include <string> // std::string #include <vector> // std::vector #include <algorithm> // std::sort #include "Student_info.h" // Student_info, read #include "extract_fails.h" // extract_fails #include "grade.h" // grade using std::cin; using std::cout; using std::endl; using std::string; using std::vector; using std::sort; int main() { vector<Student_info> students; Student_info record; // read and store all the student's data. while (read(cin, record)) students.push_back(record); // Extract the failed students vector<Student_info> students_failed = extract_fails(students); // sort vectors sort(students.begin(),students.end(),compare); sort(students_failed.begin(),students_failed.end(),compare); // Report passing students cout << "These students have passed." << endl; for (vector<Student_info>::const_iterator i = students.begin(); i != students.end(); ++i) cout << i->name << " (" << grade(*i) << ")" << endl; // Report failing students cout << "These students have failed." << endl; for (vector<Student_info>::const_iterator i = students_failed.begin(); i != students_failed.end(); ++i) cout << i->name << " (" << grade(*i) << ")" << endl; return 0; }
extract_fails.cpp
#include <vector> // std::vector #include <algorithm> // std::remove_copy_if #include "Student_info.h" #include "fgrade.h" #include "pgrade.h" using std::vector; // A two-pass solution to extract the failed students // (S6.3.1/117) vector<Student_info> extract_fails(vector<Student_info>& students) { vector<Student_info> fail; remove_copy_if(students.begin(), students.end(), back_inserter(fail), pgrade); students.erase(remove_if(students.begin(), students.end(), fgrade), students.end() ); return fail; }
fgrade.cpp
#include "Student_info.h" // Student_info #include "grade.h" // grade // predicate to determine whether a student failed // (S5.1/75) bool fgrade(const Student_info& s) { return grade(s) < 60; }
grade.cpp
#include <stdexcept> #include <vector> #include "grade.h" #include "median.h" #include "Student_info.h" using std::domain_error; using std::vector; // definitions for the grade functions from S4.1/52, S4.1.2/54, S4.2.2/63 // compute a student's overall grade from midterm and final exam // grades and homework grade (S4.1/52) double grade(double midterm, double final, double homework) { return 0.2 * midterm + 0.4 * final + 0.4 * homework; } // compute a student's overall grade from midterm and final exam grades // and vector of homework grades. // this function does not copy its argument, because median (function) does it for us. // (S4.1.2/54) double grade(double midterm, double final, const vector<double>& hw) { if (hw.size() == 0) throw domain_error("student has done no homework"); return grade(midterm, final, median(hw)); } // this function computes the final grade for a Student_info object // (S4.2.2/63) double grade(const Student_info& s) { return grade(s.midterm, s.final, s.homework); }
median.cpp
// source file for the median function #include <algorithm> #include <stdexcept> #include <vector> using std::domain_error; using std::sort; using std::vector; // compute the median of a vector<double> // (S4.1.1/53) double median(vector<double> vec) { typedef vector<double>::size_type vec_sz; vec_sz size = vec.size(); if (size == 0) throw domain_error("median of an empty vector"); sort(vec.begin(),vec.end()); vec_sz mid = size/2; return size % 2 == 0 ? (vec[mid] + vec[mid-1]) / 2 : vec[mid]; }
pgrade.cpp
#include "Student_info.h" // Student_info #include "fgrade.h" // fgrade // predicate to determine whether a student has passed (not failed) // (S6.3.1/117) bool pgrade(const Student_info& s) { return !fgrade(s); }
Student_info.cpp
#include "Student_info.h" using std::istream; using std::vector; // we are interested in sorting the Student_info object by the student's name bool compare(const Student_info& x, const Student_info& y) { return x.name < y.name; } // read student's name, midterm exam grade, final exam grade, and homework grades // and store into the Student_info object // (as defined in S4.2.2/62) istream& read(istream& is, Student_info& s) { // read and store the student's name and midterm and final exam grades is >> s.name >> s.midterm >> s.final; // read and store all the student's homework grades read_hw(is, s.homework); return is; } // read homework grades from an input stream into a vector<double> // (as defined in S4.1.3/57) istream& read_hw(istream& in, vector<double>& hw) { if (in) { // get rid of previous contents hw.clear(); // read homework grades double x; while (in >> x) hw.push_back(x); // clear the stream so that input will work for the next student in.clear(); } return in; }
Header Files
extract_fails.h
#ifndef GUARD_EXTRACT_FAILS_H #define GUARD_EXTRACT_FAILS_H // extract_fails.h #include <vector> #include "Student_info.h" std::vector<Student_info> extract_fails(std::vector<Student_info>&); #endif // GUARD_EXTRACT_FAILS_H
fgrade.h
#ifndef GUARD_FGRADE_H #define GUARD_FGRADE_H // fgrade.h #include "Student_info.h" // Student_info #include "grade.h" // grade bool fgrade(const Student_info&); #endif // GUARD_FGRADE_H
grade.h
#ifndef GUARD_GRADE_H #define GUARD_GRADE_H // grade.h #include <vector> #include "Student_info.h" double grade(double, double, double); double grade(double, double, const std::vector<double>&); double grade(const Student_info&); #endif // GUARD_GRADE_H
median.h
#ifndef GUARD_MEDIAN_H #define GUARD_MEDIAN_H // median.h #include <vector> double median(std::vector<double>); #endif // GUARD_MEDIAN_H
pgrade.h
#ifndef GUARD_PGRADE_H #define GUARD_PGRADE_H // pgrade.h #include "Student_info.h" // Student_info bool pgrade(const Student_info&); #endif // GUARD_PGRADE_H
Student_info.h
#ifndef GUARD_STUDENT_INFO_H #define GUARD_STUDENT_INFO_H // Student_info.h #include <iostream> #include <string> #include <vector> struct Student_info { std::string name; double midterm, final; std::vector<double> homework; }; bool compare(const Student_info&, const Student_info&); std::istream& read(std::istream&, Student_info&); std::istream& read_hw(std::istream&, std::vector<double>&); #endif // GUARD_STUDENT_INFO_H
Test Program
I now provide a set of student grades. The program separate the students to the pass and fail groups as expected.
pete 100 100 100 100 100 jon 90 90 0 0 0 mary 50 50 50 50 50 anna 40 40 0 0 0 gary 80 80 0 80 0 bob 100 100 100 0 0 ken 20 88 99 44 66 jay 99 39 40 80 0 bill 20 88 0 39 0 ^Z ^Z These students have passed. bob (60) ken (65.6) pete (100) These students have failed. anna (24) bill (39.2) gary (48) jay (51.4) jon (54) mary (50)