所有,我试图使用LINQ编写以下类的分层数据表示。任何人都可以帮助我
public class Employee
{
public Employee(int empId,int? managerId)
{
this.Id = empId;
this.MangerId = managerId;
this.Children = new List<Employee>();
}
public int Id { get; set; }
public int? MangerId { get; set; }
public string EmployeeName { get; set; }
public List<Employee> Children { get; set; }
}
样本数据
var empList = new List<Employee>
{
new Employee(1,2){EmployeeName = "Joseph"},
new Employee(2,3){EmployeeName = "Smith"},
new Employee(3,4){EmployeeName = "Bob"},
new Employee(4,null){EmployeeName = "Doug"},
new Employee(5,2){EmployeeName = "Dave"},
new Employee(6,4){EmployeeName = "Allan"}
};
,输出应该是这样的
/ * 道格 短发 艾伦 工匠 约瑟夫 戴夫
* /
非常感谢任何帮助
编辑:顶级员工的managerId为null
答案 0 :(得分:2)
使用您的模型,Employee模型不直接链接到自己。相反,我们必须使用他们的标识符来遍历层次结构。
首先,我们得到了根员工:
var rootEmp = EmpList.Single(e => e.MangerId == null);
然后,我们使用递归函数遍历层次结构:
string WalkEmployees(Employee root)
{
// Create the container of the names
var builder = new StringBuilder();
// Get the children of this employee
var children = EmpList.Where(e => e.MangerId == root.Id);
// Add the name of the current employee in the container
builder.Append(root.EmployeeName + " ");
// For each children, walk them recursively
foreach (var employee in children)
{
builder.Append(WalkEmployees(employee));
}
// Return the container of names
return builder.ToString();
}
最后,我们称之为函数:
WalkEmployees(rootEmp);
从本质上讲,递归函数垂直地遍历层次结构:
道格
- 鲍勃 - - 史密斯 - - 约瑟夫 - - 戴夫
- 艾伦
尽管如此,你还是期待一次水平步行,以便让艾伦在鲍勃之后。为此,我为您的员工添加了一个视图模型,用于描述他们在层次结构中的级别。
public class EmployeeViewModel
{
public EmployeeViewModel(Employee employee, int level)
{
Employee = employee;
Level = level;
}
public Employee Employee { get; set; }
public int Level { get; set; }
}
让员工走路的功能变为:
IEnumerable<EmployeeViewModel> WalkEmployees(Employee root, int level)
{
// Create the container of the employees
var container = new List<EmployeeViewModel> {new EmployeeViewModel(root, level)};
// Get the children of this employee
var children = EmpList.Where(e => e.MangerId == root.Id);
// For each children, walk them recursively
foreach (var employee in children)
{
container.AddRange(WalkEmployees(employee, level + 1));
}
// Return the container
return container;
}
及其电话:
var rootEmp = EmpList.Single(e => e.MangerId == null);
var employees = WalkEmployees(rootEmp, 0);
// Order the employees by its level in the hierarchy
var orderedEmployees = employees.OrderBy(vm => vm.Level);
// Display the names
foreach (var orderedEmployee in orderedEmployees)
{
Console.Write(orderedEmployee.Employee.EmployeeName + " ");
}
你得到这个结果:
道格
- 鲍勃 - 艾伦
- - 史密斯 - - 约瑟夫 - 戴夫
<强>加成强>
由于模型之间缺乏联系,您的模型很难处理。这是一个更强大的建议:
public class Employee
{
#region Constructors
public Employee()
{
Employees = new List<Employee>();
}
public Employee(string name) : this()
{
Name = name;
}
public Employee(string name, Employee manager) : this(name)
{
Manager = manager;
}
public Employee(string name, Employee manager, params Employee[] employees) : this(name, manager)
{
Employees.AddRange(employees);
}
#endregion
#region Properties
public List<Employee> Employees { get; set; }
public int Id { get; set; }
public Employee Manager { get; set; }
public string Name { get; set; }
#endregion
}
您现在可以像这样生成您的员工:
/// <summary>
/// Generates the employees in a hierarchy way.
/// </summary>
/// <returns>Returns the root employee.</returns>
Employee GenerateEmployees()
{
var doug = new Employee("Doug");
doug.Employees.Add(new Employee("Allan", doug));
var bob = new Employee("Bob", doug);
doug.Employees.Add(bob);
var smith = new Employee("Smith", bob);
bob.Employees.Add(smith);
smith.Employees.Add(new Employee("Joseph", smith));
smith.Employees.Add(new Employee("Dave", smith));
return doug;
}
你的步行功能变为:
string WalkEmployees(Employee root)
{
var builder = new StringBuilder();
builder.Append(root.Name + " ");
foreach (var employee in root.Employees)
{
builder.Append(WalkEmployees(employee));
}
return builder.ToString();
}
如果您使用EntityFramework使用导航属性设计数据库,则此实现更有意义。
答案 1 :(得分:0)
尝试:
string text = string.Join(" ",
from i in empList
orderby i.MangerId.HasValue, i.MangerId descending
select i.EmployeeName);