我从外部来源收到以下列表(更像是联接表):
请注意,在某些情况下,一个人向一个以上的人报告。在此示例C001中。
List<DirectReport> list = new List<DirectReport>()
{
new DirectReport(){ EmployeeId = "B001", ReportsTo = "A001" },
new DirectReport(){ EmployeeId = "B002", ReportsTo = "A001" },
new DirectReport(){ EmployeeId = "B003", ReportsTo = "A002" },
new DirectReport(){ EmployeeId = "B004", ReportsTo = "A003" },
new DirectReport(){ EmployeeId = "C001", ReportsTo = "B001" },
new DirectReport(){ EmployeeId = "C001", ReportsTo = "B003" },
new DirectReport(){ EmployeeId = "C002", ReportsTo = "B002" },
...
};
要获得C001的所有直接上级,我提出了以下建议:
IEnumerable<string> listC001sSuperiors = list.Where(x => x.EmployeeId == "C001").Select(y => y.ReportsTo);
这将产生:
"B001"
"B003"
我如何包括所有上级,包括其直接上级的上级等等?
所需的C001结果:
"B001"
"B003"
"A001"
"A002"
答案 0 :(得分:6)
可接受的答案有效,但是如果报告列表很大或针对它运行的查询数量很大,则此解决方案效率不高。在最坏的情况下,它还会分配大量子列表,这会产生收集压力。您可以做得更好。
要创建有效的解决方案,首先要做的是创建更好的数据结构:
static IDictionary<string, IEnumerable<string>> ToDictionary(
this List<DirectReport> reports)
{
// Fill this in
}
我们这里想要的是多学科词典。也就是说,给定报告的ID,该词典将返回一系列 direct 管理器。实现此数据结构应该很简单,或者在各种程序包中都可以使用第三方实现。 请注意,我们假设如果id没有管理者,则多字典返回空序列,因此请确保保持不变。
有了这些,就可以制作一个遍历算法:
static IEnumerable<T> BreadthFirst(
T item,
Func<T, IEnumerable<T>> children
)
{
var q = new Queue<T>();
q.Enqueue(item);
while(q.Count != 0)
{
T t = q.Dequeue();
yield return t;
foreach(T child in children(t))
q.Enqueue(child);
}
}
请注意,此解决方案不是递归的。该答案的堆栈消耗是恒定的,而不取决于图的拓扑。
现在我们有了这两个工具,您的问题可以直接解决:
var d = reports.ToDictionary();
var r = BreadthFirst("C001", x => d[x]).Skip(1);
“跳过一个”将从序列中删除该项目,因为您希望经理关系的可传递性关闭,而不是传递性反身性关闭。
练习:假设图形可以包含一个循环。您可以修改BreadthFirst
来检测并跳过第二次遇到的循环吗?您可以用四行(或更少)行新代码来做到这一点吗?
锻炼:类似地实施DepthFirst
。
答案 1 :(得分:4)
在DotNetFiddle中进行了测试,列表为静态。
在DotNetFiddle中使用列表作为变量进行了测试。
您可以使用递归函数来查找管理器,直到无法再获得一个。以下是查找整棵树的一种方法。如果您可以将直接报告列表设为静态,则无需将其传递出去。
navController
,您将在main like中使用以上内容,
fab.setOnClickListener { view ->
when (navController.currentDestination?.id) {
R.id.nav_home -> doSomething()
R.id.nav_gallery -> doSomethingElse()
...
}
}
输出
public static List<DirectReport> list = new List<DirectReport>()
{
new DirectReport() { EmployeeId = "B001", ReportsTo = "A001"},
new DirectReport(){EmployeeId = "B002", ReportsTo = "A001"},
new DirectReport() {EmployeeId = "B003", ReportsTo = "A002"},
new DirectReport() {EmployeeId = "B004", ReportsTo = "A003"},
new DirectReport() {EmployeeId = "C001", ReportsTo = "B001"},
new DirectReport() {EmployeeId = "C001", ReportsTo = "B003"},
new DirectReport() {EmployeeId = "C002", ReportsTo = "B002"},
new DirectReport() {EmployeeId = "A002", ReportsTo = "C001"},
};
public class DirectReport
{
public string EmployeeId { get; set; }
public string ReportsTo { get; set; }
}
public static void ReportsTo(string employeeId, List<string> results)
{
var managers = list.Where(x => x.EmployeeId.Equals(employeeId)).Select(x => x.ReportsTo).ToList();
if (managers != null && managers.Count > 0)
foreach (string manager in managers)
{
if (results.Contains(manager))
continue;
results.Add(manager);
ReportsTo(manager, results);
}
}