【问题标题】:Check if list of managers contains an employee in any of its manager's lists of employees that's also a manager检查经理列表是否包含其经理的任何员工列表中的员工,该员工也是经理
【发布时间】:2020-03-12 10:11:00
【问题描述】:

我得到一个类似于下面的 SOAP 响应:

<Record>
    <EmployeeId>1</EmployeeId>
    <ManagerId>5</ManagerId>
</Record>
<Record>
    <EmployeeId>9</EmployeeId>
    <ManagerId>7</ManagerId>
</Record>

我创建了一个具有以下属性的 Manager 类:

class Manager
    {
        public int Id { get; set; }
        public List<int> Employees { get; set; }
    }

然后我遍历响应中的记录以填充经理列表:

List<Manager> managers = new List<Manager>();

foreach (Record record in records)
{
    Manager manager = managers.Find(m => m.Id == ManagerId);

    if (manager == null)
    {
            manager = new Manager
            {
                Id = ManagerId,
                Employees = new List<int>
                {
                    EmployeeId
                },
            };
            managers.Add(manager);
    }

    else
    {
        if (!manager.Employees.Contains(EmployeeId))
            {
                manager.Employees.Add(EmployeeId);
            }
    }
}

问题是,如果经理的员工列表中有另一位经理,我需要将第二位经理的员工添加到第一位经理的员工列表中,并且如果这些员工中的任何一位也是经理,我也需要添加他们,这深入多个层次。

我想这将需要某种递归,我尝试过的一切都变得过于复杂且效率非常低。

我应该使用其他东西而不是包含列表的对象列表吗? 或者谁能​​指出我正确的方向?

【问题讨论】:

  • 您是否有理由在添加之前检查员工列表是否包含员工(即您是否从服务中获取重复记录)?
  • @theMayer 是的,有重复记录,同一员工的多个经理的记录,以及自己作为经理的员工的记录。
  • 好的,所以编写清理逻辑意味着你必须定义它是什么。除非你处理好,否则以自我为经理的员工将导致无限循环。

标签: c# list recursion


【解决方案1】:

性能下降的原因如下:

Manager manager = managers.Find(m =&gt; m.Id == ManagerId);

此行对列表中的每个员工调用一次,其实现是循环并返回第一个匹配项。相反,您需要设置一个Dictionary&lt;int, Manager&gt; 来包含您的记录。假设没有重复的记录(即Id 属性相同的记录),那么以下将起作用:

public class Manager
{
    public readonly int ManagerId;
    public readonly int EmployeeId;
    public readonly List<int> Employees = new List<int>();

    public Manager(int employeeId, int managerId) {
        this.ManagerId = managerId;
        this.EmployeeId = employeeId;
    }
}

var dict = records.Select(o => new Manager(o.EmployeeId, o.ManagerId))
                  .ToDictionary(o => o.EmployeeId);
foreach (var record in records)
{
    Manager manager;
    dict.TryGetValue(record.ManagerId, out manager);
    // recursively walk up the tree and add the record to each parent, etc.
    while (manager != null) {
        manager.Employees.Add(record.EmployeeId);
        dict.TryGetValue(manager.ManagerId, out manager);
    }
}

请注意,我将更新 Manager 的构造函数以接受员工和经理 ID 并初始化列表。

【讨论】:

  • 注意我没有测试过这个 - 你可以这样做。由于 int 的行为方式(即 value 永远不会为 null),您可能会遇到一些奇怪的情况,即员工没有经理(顶级根)。
  • 这是一个非常优雅的解决方案。如果没有重复记录,它将按原样完美运行。不过,我认为我应该能够适应我的需要,非常感谢!
  • 最好通过使用哈希集而不是列表来消除重复。
  • 是的,你是对的。另一个问题是同一员工在创建字典时为不同的经理拥有多条记录。
【解决方案2】:

您可以在 xml linq 中使用字典在一条指令中完成:

using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);
            Dictionary<int, List<int>> dict = doc.Descendants("Record")
                .GroupBy(x => (int)x.Element("ManagerId"), y => (int)y.Element("EmployeeId"))
                .ToDictionary(x => x.Key, y => y.ToList());
        }
    }
}

【讨论】:

  • OP 想要一份我提供的每个管理人员的员工列表。
  • @jdweng 谢谢你的回答,比我以前的好多了。除了您提供的内容之外,我要求的是一种递归检查经理的员工是否也是经理的方法,如果是,则将他们的员工添加到父经理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多