-2

I have a c# project, and I've created a class called Employees.
Inside this class, I have a new list:

public class Employees
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? ManagerId { get; set; }
    public List<Employees> employees { get; set; }
}

Imagine that I have the following structure shown in the image:
companytree

Then in the main program, I have this structure to represent the picture above:

class Program
{
    static void Main(string[] args)
    {
        var root = new Employees()
        {
            Id = 15,
            Name = "President",
            employees = new List<Employees>()
            {
                new Employees() {

                    Id = 23, ManagerId = 15, Name = "Director23",
                    employees = new List<Employees>()
                    {
                        new Employees() {
                            Id = 21, ManagerId = 23, Name = "Manager21",
                            employees = new List<Employees>()
                            {
                                new Employees() { Id = 31, ManagerId=21, Name = "Employee31" },
                                new Employees() { Id = 41, ManagerId=21, Name = "Employee41" },
                                new Employees() { Id = 51, ManagerId=21, Name = "Employee51" }
                            }
                        },

                        new Employees() {
                            Id = 22, ManagerId = 23, Name = "Manager22",
                            employees = new List<Employees>()
                            {
                                new Employees() { Id = 32, ManagerId=22, Name = "Employee32" },
                                new Employees() { Id = 42, ManagerId=22, Name = "Employee42" },
                                new Employees() { Id = 52, ManagerId=22, Name = "Employee52" }
                            }
                        }
                    }
                },

                new Employees() {

                    Id = 25, ManagerId = 15, Name = "Director25",
                    employees = new List<Employees>()
                    {
                        new Employees() {
                            Id = 51, ManagerId = 25, Name = "Manager51",
                            employees = new List<Employees>()
                            {
                                new Employees() { Id = 61, ManagerId=51, Name = "Employee61" },
                                new Employees() { Id = 71, ManagerId=51, Name = "Employee71" },
                                new Employees() { Id = 81, ManagerId=51, Name = "Employee81" }
                            }
                        },

                        new Employees() {
                            Id = 62, ManagerId = 25, Name = "Manager62",
                            employees = new List<Employees>()
                            {
                                new Employees() { Id = 72, ManagerId=62, Name = "Employee72" },
                                new Employees() { Id = 82, ManagerId=62, Name = "Employee82" }
                            }
                        }
                    }
                }

            }
        };

        Console.ReadLine();
    }
}

How to create a function where I pass the tree root list of the employee and the ID of any employee of the company and you need to return your manager closer or higher and also the employee itself.

Remembering that you could pass the ID of a director (you would have to return the president), the ID of the manager(you would have to return the director), the ID of the employee (you would have to return the manager), the ID of the presidente return himself.

What better way to do this research taking into account that we can have a much larger hierarchical structure than this example. It would be costly to scan all lists.

Use hastable, dictionary, hashset??

devweb
  • 1
  • 1
  • You should work on your naming conventions and casing... `Employees` should not be your class name, it should be `Employee` (its a single entity). `employees` should be `Subordinates` or something that _actually_ describes what it is. Never mix up casing like that. – maccettura Oct 11 '17 at 20:03
  • I agree with you thank you, in the rush to put the post I committed this error should be Employee. The structure of the classes is not real, but only to demonstrate how we could do this research in this tree structure – devweb Oct 11 '17 at 20:15
  • I'd go with hashset (if speed matters](https://stackoverflow.com/questions/2728500/hashsett-versus-dictionaryk-v-w-r-t-searching-time-to-find-if-an-item-exist). I would use the employee ID as the key and then an object with an Employee pointer and either top-down or bottom-up list of IDs as the value. – DSway Oct 11 '17 at 20:18

3 Answers3

0

A recursive function is generally used to search a tree. I assumed you fix the variable names as suggested:

public static Employee FindById(Employee root, int id) {
    if (root.Id == id)
        return root;
    else if (root.Employees != null) {
        foreach (var e in root.Employees) {
            var pe = FindById(e, id);
            if (pe != null)
                return pe;
        }
    }
    return null;
}

To use, find the employee and then the manager:

var emp = FindById(root, 51);
var manager = emp.ManagerId.HasValue ? FindById(root, emp.ManagerId.Value) : null;
NetMage
  • 26,163
  • 3
  • 34
  • 55
  • Yes, I used the names as an example. Your solution works, but I am looking for not read all tree more than once, and improve the search. I don't know what you think to transform that list(tree) in a dictionary or HashSet? – devweb Oct 11 '17 at 22:23
  • Well, perhaps a tree isn't the proper data structure to use in that case. The @DependencyInjection answer suggests converting the tree to a `Dictionary` and using that, and while it lacks error checking, the main problem I see is what happens when you update the tree? – NetMage Oct 11 '17 at 22:29
0

Add there two functions :

public static IDictionary<int, Employees> EmployeesToDictionary(Employees employees)
{
    var dictionary = new Dictionary<int, Employees>();
    EmployeesToDictionary(employees, dictionary);
    return dictionary;
}

private static void EmployeesToDictionary(Employees employees, IDictionary<int, Employees> dictionary)
{
    if (employees == null) return;
    dictionary.Add(employees.Id, employees);
    if (employees.employees == null) return;
    foreach (var sub in employees.employees)
    {
        EmployeesToDictionary(sub);
    }
}

And usage :

var id = 5;
var dict = EmployeesToDictionary(root);
var employee = dict[id];
var manager = dict[employee.ManagerId.Value];

Edit : @haindl Documentation is an admission of failure Yeah you're right. @devweb I have added the check for the exception. The dictionnary is created only one time, check again

  • Welcome to StackOverflow! It would be nice if you could explain your code a little bit so we can understand what you are proposing as an answer. – haindl Oct 11 '17 at 20:46
  • In "public static IDictionary EmployeesToDictionary(Employees employees)" you can not use "var dictionary = new Dictionary();" Because you are always creating the dictionary again. Also in the foreach if you have an employee wihout children it`s going to give you a exception. – devweb Oct 11 '17 at 22:12
  • @devweb You may want to read the answer again more carefully. – NetMage Oct 11 '17 at 22:28
0

If you want to do a traversal only once, there are this possibility :

public static void FindById(Employees root, int id, out Employees employees, out Employees manager)
{
    employees = manager = null;
    // todo stack
    var stack = new Stack<Employees>();
    stack.Push(root);
    // all managers seens
    var managers = new List<Employees>();
    while (stack.Count > 0)
    {
        var e = stack.Pop();
        if (e.Id == id) // if found
        {
            employees = e;
            manager = managers.FirstOrDefault(m => m.Id == e.ManagerId);
            return;
        }
        else if (e.employees != null)
        {
            // add only managers with employee
            managers.Add(e);
            foreach (var ep in e.employees)
            {
                stack.Push(ep);
            }
        }
    }
}