LINQ Flatten Circular Reference

时间:2018-04-23 19:19:46

标签: c# linq

我有一个用户对象:

class user
{
  int userId {get; set;}
  string name {get; set}
  int supervisorId {get; set}
}

每个supervisorId也是users表中的useId。我正试图找到一种合理的方法来构建用户主管的层次结构,一直到顶级人员。所以选择一个用户的supervisorID,然后选择那个主管的supervisorId等等。我现在正在处理一个越来越难看的循环,但希望某人有更优雅的东西。

3 个答案:

答案 0 :(得分:3)

首先让你的用户对象不那么可怕:

class User
{
  public int Id {get; private set;}
  public string Name {get; private set;}
  private int supervisorId;
  public User Supervisor 
  {
    get { ... implement it ... } 
  }

对于没有主管的用户,请Supervisor返回null

现在你可以实现:

  public IEnumerable<User> ManagementChain()
  {
    User current = this.Supervisor;
    while(current != null) 
    {
      yield return current;
      current = current.Supervisor;
    }
  }
}

你已经完成了;现在,您可以为任何用户提供一系列主管。最顶层的用户有一个空的主管序列。

答案 1 :(得分:1)

基于原始帖子中的类,我总结了一个如何使用递归方法的例子,以便在用户找到主管之前沿着列表(或任何可用的数字)前进。我确实假设顶层的主管有一个设置的主管ID来识别他们作为顶级。为了能够展示这个,我现在把0放在那里。

有两个示例,一个仅返回主管,另一个返回整个层次结构。

public class Program  {

private const int SupervisorId = 0;

static void Main(string[] args)
{
  List<user> users = new List<user>();
  users.Add(new user {userId = 1, name = "1", supervisorId = SupervisorId});
  users.Add(new user { userId = 2, name = "2", supervisorId = SupervisorId});
  users.Add(new user { userId = 3, name = "3", supervisorId = 1 });
  users.Add(new user { userId = 4, name = "4", supervisorId = 1 });
  users.Add(new user { userId = 5, name = "5", supervisorId = 2 });
  users.Add(new user { userId = 6, name = "6", supervisorId = 5 });

  var nonSupervisors = users.Where(u => u.supervisorId != SupervisorId);
  Dictionary<user, user> userAndSupervisor = nonSupervisors.ToDictionary(user => user, user => FindSupervisor(users, user));
  Dictionary<user, List<user>> userAndHierarchy =nonSupervisors.ToDictionary(user => user, user => FindSupervisorHierarchy(users, user));
}

static user FindSupervisor(List<user> users, user user)
{
  var parentUser = users.FirstOrDefault(u => u.userId == user.supervisorId);
  if (parentUser?.supervisorId != SupervisorId)
  {
    parentUser = FindSupervisor(users, parentUser);
  }
  return parentUser;
}

static List<user> FindSupervisorHierarchy(List<user> users, user user)
{
  var parentUsers = users.Where(u => u.userId == user.supervisorId);
  if (parentUsers.All(x => x.supervisorId != SupervisorId))
  {
    parentUsers = parentUsers.Concat(FindSupervisorHierarchy(users, parentUsers.FirstOrDefault()));
  }
  return parentUsers.ToList();
}
}

答案 2 :(得分:0)

您是否只是想找到一种方法来确定特定用户是否是最佳人选?一个空的SupervisorId不会表明这一点吗?

你可以使SupervisorId可以为空

int? supervisorId

while(supervisorId != null)
{
    //Check supervisor's supervisorId
}