0

Sorry for the long post. I had this coding problem for an interview but couldnt figure out. Would really appreciate if someone could please help. Will prepare me better next time. There are two classes

class Emp
{
    public string Name { get; set; }
    public string Manager { get; set; }
}
class Roo
{
    public string Name { get; set; }
    public List<Roo> Children { get; set; }
}

Input data is a list of employee objects with name and their manager. Since RH has empty manager, it will be the root of top down output.

 var empList = new List<Emp>();
 empList.Add(new Emp { Name = "TD", Manager = "AV" });
 empList.Add(new Emp { Name = "DL", Manager = "AV" });
 empList.Add(new Emp { Name = "AV", Manager = "JS" });
 empList.Add(new Emp { Name = "JS", Manager = "RH" });
 empList.Add(new Emp { Name = "KM", Manager = "DD" });
 empList.Add(new Emp { Name = "DD", Manager = "RH" });
 empList.Add(new Emp { Name = "RH", Manager = "" });

I need to convert this list into an object of type Roo. If an employee has a manager, they become the children of the manager. Output json looks like this

Output

My attempt is as follows but something is not right in the recursion function. Can someone please help.

 var leader = empList.Where(x => x.Manager == string.Empty).FirstOrDefault();
 var roo = new Roo();
 var children = new List<Roo>();
 roo.Name = leader.Name;
 GetChildren(empList, leader.Name, ref children);
 // Convert roo to Json


  void GetChildren(List<Emp> empList, string name, ref List<Roo> children)
  {
     var list = empList.Where(x => x.Manager == name).ToList();
     if (list.Any())
     {
         var roo = new Roo();
         foreach(var l in list)
         {
             var newlist = empList.Where(x => x.Manager == l.Name).ToList();
             if (newlist.Any())
                 GetChildren(newlist, l.Name, ref children);
             else
             {
                 roo = new Roo { Name = l.Name, Children = null };
                 children.Add(roo);
             }
         }
     }
  }
Gellio Gao
  • 835
  • 6
  • 19
blue piranha
  • 3,706
  • 13
  • 57
  • 98
  • 1
    Was recursion a requirement? – hijinxbassist Jun 17 '21 at 23:35
  • Yes. But do you have a solution without recursion? Thank you. – blue piranha Jun 18 '21 at 00:42
  • Meh, 2 passes. `var people = empList.ToDictionary(e => e.Name, e => new Roo {...}); foreach(var e in empList) people[e.Manager].Chilren.Add(people[e.Name]);` – Jeremy Lakeman Jun 18 '21 at 01:06
  • @JeremyLakeman Sorry didnt understand your code. I see that you are converting a dictionary out of the empList. But what are the three ... when creating Roo? What would be the values of Name and Children in that? Thank you – blue piranha Jun 18 '21 at 02:07
  • I left that out because it should be obvious, you already know how to create a `Roo` from an `Emp`. You set the name and probably create an empty list of children. – Jeremy Lakeman Jun 18 '21 at 02:56

1 Answers1

0

Recursively:

var mainRoo = GetRoosManagedBy(empList, "")[0];

public List<Roo> GetRoosManagedBy(List<Emp> emps, string manager) {
    return emps.Where(e => e.Manager == manager)
      .Select(e => new Roo {
        Name = e.Name,
        Children = GetRoosManagedBy(emps, e.Manager)
   }).ToList();
}

The recursion stops because at some point many employees are not managers so the Where returns 0 results and the Select is never run, never calling GetRoos

I don't like it as much as JL's suggestion(which I would also go for) of creating an index of Roos and linking them up

var index = empList.ToDictionary(
    e => e.Name, 
    e => new Roo {
        Name = e.Name,
        Children = new List<Roo>()
    } 
); 

foreach(var e in empList)     
    index[e.Manager].Children.Add(index[e.Name]);

var mainRoo = index[""];

Whereas your (and my) recursive approaches essentially do a "get emps of whom this emp is a manager", the indexed approach provides a fast way to find a manager so that as the list of emps is iterated and the manager of some emp e becomes known, they can be quickly found and have e assigned as underneath them. All emps are indexed but only managers are ever retrieved. At the end the index is discarded

Also worth noting that your list of emps seems to be sorted such that it could be traversed backwards in a single pass, creating the tree

var index = new Dictionary<string, Roo>();
empList.Reverse();
foreach(var e in empList){
    //make a Roo for this emp
    var r = new Roo { Name = e.Name, Children = new List<Roo>() };

    //index the emp
    index[e.Name] = r;

    //the first time we loop we should set the top level person and make no manager assignment (otherwise they will manager themselves and tree will have a loop)
    if(index.Count==1) 
        index[""] = r;
    else //else find this persons manager and assign them a manager of this person 
        index[e.Manager].Children.Add(r);
}
var mainRoo = index[""];

Note that the list reverse performs an inplace modification of the list and here is used for convenience; consider a for with decrementing counter in prod ( linq reverse is not so performant either)

Caius Jard
  • 72,509
  • 5
  • 49
  • 80