Welcome! Today, we are going to explore an engaging task that involves managing employee records within a company. Specifically, we will work with nested dictionaries and lists to add projects and tasks for employees and to retrieve those tasks as needed. This exercise will help you understand how to manipulate hierarchical data structures efficiently using C#
.
Let's start by discussing the methods we will implement in our EmployeeRecords
class.
AddProject(string employeeId, string projectName)
- This method adds a new project to an employee's list of projects. If the project already exists for that employee, the method returnsfalse
. Otherwise, it adds the project and returnstrue
.AddTask(string employeeId, string projectName, 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 returnsfalse
. If the task is added successfully, it returnstrue
.GetTasks(string employeeId, string projectName)
- This method retrieves all tasks for a specified project of an employee. If the project does not exist for that employee, the method returnsnull
. Otherwise, it returns the list of tasks._Traverse(string employeeId, string projectName)
- This private method helps to locate the nested structure for a given employee and project. If the path is valid and exists, it returns the target object. If it is invalid or does not exist, it returnsnull
.
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#1using System; 2using System.Collections.Generic; 3 4public class EmployeeRecords 5{ 6 private Dictionary<string, Dictionary<string, List<string>>> records; 7 8 public EmployeeRecords() 9 { 10 records = new Dictionary<string, Dictionary<string, List<string>>>(); 11 } 12} 13 14public class Program 15{ 16 public static void Main() 17 { 18 var records = new EmployeeRecords(); 19 Console.WriteLine(records); 20 } 21}
In this initial setup, we define the EmployeeRecords
class and create an instance variable records
that is a nested dictionary. This structure will be used to store employee records, where each key is an employee ID and each value is another dictionary holding projects and their respective tasks.
The _Traverse
method helps to locate the nested structure for a given employee and project. If the path is valid and exists, it returns the target object. If the path is invalid or does not exist, it returns null
.
Here is the breakdown of how _Traverse
works:
C#1using System; 2using System.Collections.Generic; 3 4public class EmployeeRecords 5{ 6 private Dictionary<string, Dictionary<string, List<string>>> records; 7 8 public EmployeeRecords() 9 { 10 records = new Dictionary<string, Dictionary<string, List<string>>>(); 11 } 12 13 private List<string>? _Traverse(string employeeId, string projectName) 14 { 15 if (!records.ContainsKey(employeeId)) 16 { 17 return null; 18 } 19 var employeeProjects = records[employeeId]; 20 if (projectName != null && !employeeProjects.ContainsKey(projectName)) 21 { 22 return null; 23 } 24 return projectName != null ? employeeProjects[projectName]! : null; 25 } 26} 27 28public class Program 29{ 30 public static void Main() 31 { 32 var records = new EmployeeRecords(); 33 Console.WriteLine(records); 34 } 35}
This method checks if the employeeId
exists in the records
dictionary and optionally checks for a projectName
. If either is invalid, it returns null
.
We'll implement the AddProject
method and provide all necessary components for it to be executable.
C#1using System; 2using System.Collections.Generic; 3 4public class EmployeeRecords 5{ 6 private Dictionary<string, Dictionary<string, List<string>>> records; 7 8 public EmployeeRecords() 9 { 10 records = new Dictionary<string, Dictionary<string, List<string>>>(); 11 } 12 13 public bool AddProject(string employeeId, string projectName) 14 { 15 if (!records.ContainsKey(employeeId)) 16 { 17 records[employeeId] = new Dictionary<string, List<string>>(); 18 } 19 if (records[employeeId].ContainsKey(projectName)) 20 { 21 return false; 22 } 23 else 24 { 25 records[employeeId][projectName] = new List<string>(); 26 return true; 27 } 28 } 29} 30 31public class Program 32{ 33 public static void Main() 34 { 35 var records = new EmployeeRecords(); 36 Console.WriteLine(records.AddProject("E123", "ProjectA")); // Returns True 37 Console.WriteLine(records.AddProject("E123", "ProjectA")); // Returns False 38 } 39}
In this implementation, the AddProject
method ensures that each employee can have unique projects. It checks if the specified projectName
already exists for the given employeeId
within the records
dictionary. If the project does not exist, it initializes a new entry with an empty list for tasks and returns True
. This method highlights basic dictionary operations used to manage nested data effectively.
We'll next implement the AddTask
method, along with all components needed for it to be executable.
C#1using System; 2using System.Collections.Generic; 3 4public class EmployeeRecords 5{ 6 private Dictionary<string, Dictionary<string, List<string>>> records; 7 8 public EmployeeRecords() 9 { 10 records = new Dictionary<string, Dictionary<string, List<string>>>(); 11 } 12 13 private List<string>? _Traverse(string employeeId, string projectName) 14 { 15 if (!records.ContainsKey(employeeId)) 16 { 17 return null; 18 } 19 var employeeProjects = records[employeeId]; 20 if (projectName != null && !employeeProjects.ContainsKey(projectName)) 21 { 22 return null; 23 } 24 return projectName != null ? employeeProjects[projectName]! : null; 25 } 26 27 public bool AddProject(string employeeId, string projectName) 28 { 29 if (!records.ContainsKey(employeeId)) 30 { 31 records[employeeId] = new Dictionary<string, List<string>>(); 32 } 33 if (records[employeeId].ContainsKey(projectName)) 34 { 35 return false; 36 } 37 else 38 { 39 records[employeeId][projectName] = new List<string>(); 40 return true; 41 } 42 } 43 44 public bool AddTask(string employeeId, string projectName, string task) 45 { 46 var project = _Traverse(employeeId, projectName); 47 if (project == null) 48 { 49 return false; 50 } 51 project.Add(task); 52 return true; 53 } 54 55 public List<string>? GetTasks(string employeeId, string projectName) 56 { 57 return _Traverse(employeeId, projectName); 58 } 59} 60 61public class Program 62{ 63 public static void Main() 64 { 65 var records = new EmployeeRecords(); 66 records.AddProject("E123", "ProjectA"); 67 Console.WriteLine(records.AddTask("E123", "ProjectA", "Task1")); // Returns True 68 Console.WriteLine(records.AddTask("E123", "NonExistentProject", "Task3")); // Returns False 69 } 70}
In this step, the AddTask
method is introduced, which adds a task to a specified project for an employee. By utilizing the _Traverse
helper method, it checks if the specified project exists under the given employee ID. If the project is present, it adds the task to the project’s task list and returns true
. If the project does not exist, it returns false
. This structure demonstrates the efficient traversal and update of nested data.
Lastly, we'll implement the GetTasks
method, along with all necessary components for it to be executable.
C#1using System; 2using System.Collections.Generic; 3 4public class EmployeeRecords 5{ 6 private Dictionary<string, Dictionary<string, List<string>>> records; 7 8 public EmployeeRecords() 9 { 10 records = new Dictionary<string, Dictionary<string, List<string>>>(); 11 } 12 13 private List<string>? _Traverse(string employeeId, string projectName) 14 { 15 if (!records.ContainsKey(employeeId)) 16 { 17 return null; 18 } 19 var employeeProjects = records[employeeId]; 20 if (projectName != null && !employeeProjects.ContainsKey(projectName)) 21 { 22 return null; 23 } 24 return projectName != null ? employeeProjects[projectName]! : null; 25 } 26 27 public bool AddProject(string employeeId, string projectName) 28 { 29 if (!records.ContainsKey(employeeId)) 30 { 31 records[employeeId] = new Dictionary<string, List<string>>(); 32 } 33 if (records[employeeId].ContainsKey(projectName)) 34 { 35 return false; 36 } 37 else 38 { 39 records[employeeId][projectName] = new List<string>(); 40 return true; 41 } 42 } 43 44 public bool AddTask(string employeeId, string projectName, string task) 45 { 46 var project = _Traverse(employeeId, projectName); 47 if (project == null) 48 { 49 return false; 50 } 51 project.Add(task); 52 return true; 53 } 54 55 public List<string>? GetTasks(string employeeId, string projectName) 56 { 57 return _Traverse(employeeId, projectName); 58 } 59} 60 61public class Program 62{ 63 public static void Main() 64 { 65 var records = new EmployeeRecords(); 66 records.AddProject("E123", "ProjectA"); 67 records.AddTask("E123", "ProjectA", "Task1"); 68 var tasks = records.GetTasks("E123", "ProjectA"); // Returns List<string> with "Task1" 69 if (tasks != null) 70 { 71 Console.WriteLine(string.Join(", ", tasks)); // Outputs: Task1 72 } 73 var nonExistentTasks = records.GetTasks("E123", "NonExistentProject"); 74 Console.WriteLine(nonExistentTasks == null); // Prints True 75 } 76}
By leveraging the _Traverse
method, the GetTasks
method efficiently locates the target project within the nested dictionary structure. If the project exists, it returns the list of tasks, otherwise, it returns null
. This method exemplifies effective retrieval from hierarchical data structures, allowing easy access to manage employee tasks.
In this lesson, we successfully implemented the EmployeeRecords
class for managing projects and tasks for employees using nested dictionaries and lists in C#
. We covered methods for adding projects, adding tasks to those projects, and retrieving tasks from those projects, leveraging the _Traverse
method to handle nested data efficiently.
Understanding how to work with hierarchical data structures allows you to efficiently manage complex data hierarchies, which improves your programming skills and problem-solving abilities.