将"级别"设置为包含多个图层的嵌套列表


[{
"EmployeeID": 1,
"EmployeeName": "ABC",
"Department": "US",
"Level": null,
"ParentID": null,
"Employees": [{
"EmployeeID": 4,
"EmployeeName": "ABCD",
"Department": "US",
"Level": null,
"ParentID": 1,
"Employees": []
},
{
"EmployeeID": 6,
"EmployeeName": "ABCDS",
"Department": "US",
"Level": null,
"ParentID": 1,
"Employees": []
},
{
"EmployeeID": 7,
"EmployeeName": "ABCDS",
"Department": "US",
"Level": null,
"ParentID": 1,
"Employees": [{
"EmployeeID": 8,
"EmployeeName": "ABCD",
"Department": "US",
"Level": null,
"ParentID": 7,
"Employees": []
},
{
"EmployeeID": 9,
"EmployeeName": "ABCDS",
"Department": "US",
"Level": null,
"ParentID": 7,
"Employees": []
}
]
}
]
}]

上面是一个JSON嵌套列表,在将其序列化为C#列表对象后,我想设置Level道具,例如,员工ID 1将具有级别1,员工ID 4、6、7将具有级别2,员工ID 8、9将具有级别3。

这是一个嵌套列表,它可以有n层,我尝试过一些循环的方法,但失败了,任何一个都能帮忙吗。下面是我的课堂对象。

public class Employee
{
public int EmployeeID { get; set; }
public string EmployeeName { get; set; }
public string Department { get; set; }
public int? Level { get; set; }
public List<Employee> Employees { get; set; }
}

使用以下代码将其转换为列表对象

var jsonstring = File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "Employee.json"));
var employeeList = JsonSerializer.Deserialize<List<Employee>>(jsonstring);

这是递归编程的完美用例。然而,为了避免使用调用堆栈(其大小有限(,我们可以使用仅受系统内存技术限制的自定义堆栈。你可以这样做:

public static class EmployeeExtensions {
public static Employee PopulateLevels(this Employee e){
var employees = new Stack<Employee>();
employees.Push(e);
if(e.Level == null){
e.Level = 1;
}
while(employees.Count > 0){
var parent = employees.Pop();
foreach(var child in parent.Employees ?? Enumerable.Empty<Employee>()){
child.Level = parent.Level + 1;
employees.Push(child);
}
}
return e;
}
}

使用它:

foreach(var e in employeeList){
e.PopulateLevels();
}
//or inline with the ToList
var employeeList = JsonSerializer.Deserialize<List<Employee>>(jsonstring)
.Select(e => e.PopulateLevels()).ToList();

如果数据大小很小(甚至相当大(,我不会太关心性能,但上面的代码可能会改进如下:

public static class EmployeeExtensions {
public static Employee PopulateLevels(this Employee e){
if(e.Level == null){
e.Level = 1;
}
if(e.Employees == null) return e;
var employees = new Stack<Employee>();
employees.Push(e);             
while(employees.Count > 0){
var parent = employees.Pop();
var childLevel = parent.Level + 1;
foreach(var child in parent.Employees){
child.Level = childLevel;
if(child.Employees?.Any() ?? false){
employees.Push(child);
}
}
}
return e;
}
}

当然,基准测试总是需要看看它可以改进多少。微小的改进通常不值得付出努力。

使员工扁平化:

public static class EmployeeExtensions {
public static IEnumerable<Employee> GetAllEmployees(this Employee e){
yield return e;
if(e.Employees == null) yield break;
var employees = new Stack<Employee>();
employees.Push(e);             
while(employees.Count > 0){
var parent = employees.Pop();
foreach(var child in parent.Employees){
yield return child;
if(child.Employees?.Any() ?? false){
employees.Push(child);
}
}
}
}
}

使用

var employeeList = employeeList.SelectMany(e => e.GetAllEmployees()).ToList();