Vector of Login Records

  1. Consider that we have a text file "last.txt, which is the output generated by running the command "last -w" on lilina.
  2. For each record, we are only interested in the login name and duration between login/logout, so we define a class CLogin:
    class CLogin {
    public:
        string  name;
        int     minute;
    
        CLogin(string s, int m): name(s), minute(m) {}
        CLogin(string s, string m): name(s) {
            // minute = stoi(m.substr(0,2))*60 + stoi(m.substr(3,2));
            // g++ on lilina is too old, otherwise you should have stoi().
            minute = atoi(m.substr(0,2).c_str())*60 + atoi(m.substr(3,2).c_str());
    
        }
        friend ostream& operator<<(ostream& output, const CLogin& a) {
            output << a.name << ' ' << a.minute;
            return output;
        }
    };
  3. Assume that we have a function getLogin() which reads data from a text file and returns a vector of CLogin objects. Each CLogin object consists of two data members: a login name and the minutes of the login session.
    vector<CLogin> getLogin(const char* fn = "last.txt") {
        ifstream infile(fn);
        string line;
        vector<CLogin> logins;
        while (getline(infile, line)) {
            string name;
            string duration;
            int nStart, nLength;
            name = line.substr(0, line.find(" "));
            nStart = line.find("(")+1;
            nLength = line.find(")") - nStart;
            duration = line.substr(nStart, nLength);
    #ifdef _DEBUG
            cout << name << duration << endl;
    #endif
            logins.push_back( CLogin(name, duration) );
        }
        return logins;
    };
  4. You may test getLogin() with the following main program:
    int main()
    {
        vector<CLogin> logins = getLogin();
        for (size_t i=0; i<logins.size(); ++i) {
            cout << logins[i] << endl;
        }
        return 0;
    }
  5. The output may look like:
    solomon 44
    s109321059 8
    s109321059 7
    s109321059 0
    s110321005 12
    solomon 30
    solomon 20
    klim 8
    s108321022 251
    s108321022 5
  6. The above output is not good, because the same user has several login records. We want to aggregate them into a single record. Now you are requested to develop a loginCount() function, which will return a vector of CCount. CCount is similar to CLogin, but the second data member, which is an integer, will store the login counts instead of durations.
    class CCount {
    public:
        string  name;
        int     count;
    
        CCount(string s, int c=0): name(s), count(c) {}
    
        friend ostream& operator<<(ostream& output, const CCount& a) {
            output << a.name << ' ' << a.count;
            return output;
        }
    };
  7. This vector will be shorter than the previous one, because each user will only have a corresponding record.
  8. You may test your loginCount() with the following main program:
    vector<CLogin> loginCount(vector<CLogin>& logins);
    
    int main()
    {
        vector<CLogin> logins = getLogin("/home/solomon/CPP/last.txt");
        vector<CCount> counts = loginCount(logins);
        for (size_t i=0; i<counts.size(); ++i) {
            cout << counts[i] << endl;
        }
        return 0;
    }
    
  9. The output may look like:
    solomon 133
    s109321059 27
    s110321005 36
    klim 20
    s108321022 36
    s110321529 21
    s110321063 77
    s107321058 60
    s109321020 15
    s110321071 12