Lesson 4
Employee Records Management Using C++ with std::map and std::vector
Introduction

Welcome! Today, we are going to explore an engaging task that involves managing employee records within a company. Specifically, we will work with nested std::map and std::vector to add projects and tasks for employees and retrieve those tasks as needed. This exercise will help you understand how to manipulate nested data structures efficiently in C++.

Introducing Methods to Implement

Let's start by discussing the methods we will implement in our EmployeeRecords class.

  • bool add_project(const std::string& employee_id, const std::string& project_name) - this method adds a new project to an employee's list of projects. If the project already exists for that employee, the method returns false. Otherwise, it adds the project and returns true.
  • bool add_task(const std::string& employee_id, const std::string& project_name, const std::string& task) - this method adds a new task to a specified project for an employee. If the project does not exist for that employee, the method returns false. If the task is added successfully, it returns true.
  • std::vector<std::string> get_tasks(const std::string& employee_id, const std::string& project_name) - this method retrieves all tasks for a specified project of an employee. If the project does not exist for that employee, the method returns an empty vector. Otherwise, it returns the list of tasks.
Step 1: Basic Class Structure

Now, let's build our EmployeeRecords class step by step, ensuring we understand each component clearly.

We'll start with the basic structure of the class and initialize our data storage.

C++
1#include <iostream> 2#include <map> 3#include <vector> 4#include <string> 5 6class EmployeeRecords { 7public: 8 EmployeeRecords() = default; 9 10private: 11 std::map<std::string, std::map<std::string, std::vector<std::string>>> records; 12}; 13 14// Instantiate the class to ensure it works 15int main() { 16 EmployeeRecords records; 17 return 0; 18}

In this initial setup, we define the EmployeeRecords class and create an instance variable records that is a std::map. This map will be used to store employee records, where each key is an employee ID and each value is another map holding projects.

Step 2: Implementing `add_project` Method

Next, we'll implement the add_project method to add projects to an employee's record.

C++
1#include <iostream> 2#include <map> 3#include <vector> 4#include <string> 5 6class EmployeeRecords { 7public: 8 EmployeeRecords() = default; 9 10 bool add_project(const std::string& employee_id, const std::string& project_name) { 11 if (records[employee_id].count(project_name)) { 12 return false; 13 } else { 14 records[employee_id][project_name] = std::vector<std::string>(); 15 return true; 16 } 17 } 18 19private: 20 std::map<std::string, std::map<std::string, std::vector<std::string>>> records; 21}; 22 23// Example usage and testing 24int main() { 25 EmployeeRecords records; 26 std::cout << records.add_project("E123", "ProjectA") << std::endl; // Returns 1 (true) 27 std::cout << records.add_project("E123", "ProjectA") << std::endl; // Returns 0 (false) 28 return 0; 29}

Here, the add_project method checks if the given project_name already exists for the employee_id in the records map. If it does, the method returns false. Otherwise, it initializes an empty std::vector for the project (to hold tasks) and returns true.

Step 3: Implementing `add_task` Method

Now, we will implement the add_task method. This method relies on the availability of the existing project.

C++
1#include <iostream> 2#include <map> 3#include <vector> 4#include <string> 5 6class EmployeeRecords { 7public: 8 EmployeeRecords() = default; 9 10 bool add_project(const std::string& employee_id, const std::string& project_name) { 11 if (records[employee_id].count(project_name)) { 12 return false; 13 } else { 14 records[employee_id][project_name] = std::vector<std::string>(); 15 return true; 16 } 17 } 18 19 bool add_task(const std::string& employee_id, const std::string& project_name, const std::string& task) { 20 if (records[employee_id].count(project_name) == 0) { 21 return false; 22 } 23 records[employee_id][project_name].push_back(task); 24 return true; 25 } 26 27private: 28 std::map<std::string, std::map<std::string, std::vector<std::string>>> records; 29}; 30 31// Example usage and testing 32int main() { 33 EmployeeRecords records; 34 records.add_project("E123", "ProjectA"); 35 std::cout << records.add_task("E123", "ProjectA", "Task1") << std::endl; // Returns 1 (true) 36 std::cout << records.add_task("E123", "NonExistentProject", "Task3") << std::endl; // Returns 0 (false) 37 return 0; 38}

The add_task method first checks if the project_name exists for the employee_id in the records map. If the check fails, the method returns false. Otherwise, it appends the task to the list of tasks for the specified project and returns true.

Step 4: Implementing `get_tasks` Method

Lastly, let's implement the get_tasks method to retrieve tasks from a specified employee's project.

C++
1#include <iostream> 2#include <map> 3#include <vector> 4#include <string> 5 6class EmployeeRecords { 7public: 8 EmployeeRecords() = default; 9 10 bool add_project(const std::string& employee_id, const std::string& project_name) { 11 if (records[employee_id].count(project_name)) { 12 return false; 13 } else { 14 records[employee_id][project_name] = std::vector<std::string>(); 15 return true; 16 } 17 } 18 19 bool add_task(const std::string& employee_id, const std::string& project_name, const std::string& task) { 20 if (records[employee_id].count(project_name) == 0) { 21 return false; 22 } 23 records[employee_id][project_name].push_back(task); 24 return true; 25 } 26 27 std::vector<std::string> get_tasks(const std::string& employee_id, const std::string& project_name) { 28 if (records[employee_id].count(project_name) == 0) { 29 return {}; 30 } 31 return records[employee_id][project_name]; 32 } 33 34private: 35 std::map<std::string, std::map<std::string, std::vector<std::string>>> records; 36}; 37 38// Example usage and testing 39int main() { 40 EmployeeRecords records; 41 records.add_project("E123", "ProjectA"); 42 records.add_task("E123", "ProjectA", "Task1"); 43 for (const auto& task : records.get_tasks("E123", "ProjectA")) { 44 std::cout << task << std::endl; // Prints "Task1" 45 } 46 std::vector<std::string> tasks = records.get_tasks("E123", "NonExistentProject"); 47 std::cout << tasks.empty() << std::endl; // Returns 1 (true) 48 return 0; 49}

The get_tasks method checks if the project_name exists for the employee_id in the records map. If the check fails, the method returns an empty vector. Otherwise, it returns the list of tasks for the specified project.

Lesson Summary

In this lesson, we successfully implemented the EmployeeRecords class for managing projects and tasks for employees using nested std::map and std::vector. We covered methods for adding projects, adding tasks to those projects, and retrieving tasks from those projects.

Understanding how to work with nested data structures allows you to efficiently manage complex data hierarchies, which improves your programming skills and problem-solving abilities. I encourage you to practice similar challenges to reinforce what you learned today.

Keep coding and exploring new challenges!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.