【问题标题】:Modifying a bottom up data to top down using recursion使用递归将自下而上的数据修改为自上而下
【发布时间】:2021-06-17 22:54:35
【问题描述】:

抱歉,帖子太长了。我在面试时遇到了这个编码问题,但无法弄清楚。如果有人可以请帮助,我将不胜感激。下次会让我做好准备。 有两个类

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; }
}

输入数据是包含姓名及其经理的员工对象列表。由于 RH 有空管理器,它将是自顶向下输出的根。

 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 = "" });

我需要将此列表转换为 Roo 类型的对象。如果员工有经理,他们就会成为经理的孩子。输出json是这样的

我的尝试如下,但递归函数有问题。有人可以帮忙吗?

 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);
             }
         }
     }
  }

【问题讨论】:

  • 是否需要递归?
  • 是的。但是你有没有递归的解决方案?谢谢。
  • 嗯,2 次传球。 var people = empList.ToDictionary(e =&gt; e.Name, e =&gt; new Roo {...}); foreach(var e in empList) people[e.Manager].Chilren.Add(people[e.Name]);
  • @JeremyLakeman 抱歉没有看懂你的代码。我看到您正在从 empList 中转换字典。但是在创建 Roo 时,这三个...是什么? Name 和 Children 的值是什么?谢谢
  • 我把它省略了,因为它应该很明显,你已经知道如何从Emp 创建一个Roo。您设置名称并可能创建一个空的子列表。

标签: c#


【解决方案1】:

递归:

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();
}

递归停止,因为在某些时候许多员工不是经理,所以 Where 返回 0 结果并且 Select 永远不会运行,永远不会调用 GetRoos

我不喜欢 JL 的建议(我也会赞成)创建 Roos 索引并将它们链接起来

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[""];

虽然您(和我的)递归方法本质上是“获取此 emp 是经理的 emps”,但索引方法提供了一种快速查找经理的方法,以便迭代 emps 列表和经理一些 emp e 变得已知,可以快速找到它们并将 e 分配到它们的下方。所有 emps 都被编入索引,但只有 manager 被检索过。最后索引被丢弃

还值得注意的是,您的 emps 列表似乎是经过排序的,因此它可以在一次通过中向后遍历,从而创建树

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[""];

注意,list reverse 对列表进行了就地修改,这里是为了方便起见;考虑一个 for 在 prod 中具有递减计数器(linq reverse 也不是那么高效)

【讨论】:

    猜你喜欢
    • 2011-06-23
    • 2015-05-21
    • 1970-01-01
    • 2011-06-21
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-28
    相关资源
    最近更新 更多