cor*_*010 3 c# entity-framework
这类似于问题(在给定的子 LINQ (lambda 表达式) 的树层次结构中查找父项)。但是,我需要找到所有后代,而不是找到所有祖先。
我正在修改 Yacoub 的方法,但只设法将所有后代都放在一个分支中。
private IEnumerable<UserRole> FindAllChildrenRecursively(List<UserRole> allRoles, UserRole role)
{
var child = allRoles.FirstOrDefault(x => x.ParentId == role.Id);
if (child == null)
return Enumerable.Empty<UserRole>();
return new[] { child }.Concat(FindAllChildrenRecursively(allRoles, child));
}
Run Code Online (Sandbox Code Playgroud)
我正在修改 Yacoub 的方法,但只设法将所有后代都放在一个分支中
这是因为这一行:
var child = allRoles.FirstOrDefault(x => x.ParentId == role.Id);
Run Code Online (Sandbox Code Playgroud)
虽然它可能已经适用于寻找一个单一的父母,它不适合用于查找多个孩子。
但是您不需要递归迭代器和对allRoles列表的多次迭代。您可以使用ToLookup扩展方法创建一个快速查找结构,然后像这样执行迭代DFS:
private static IEnumerable<UserRole> FindAllChildren(List<UserRole> allRoles, UserRole role)
{
var childrenByParentId = allRoles.ToLookup(r => r.ParentId);
var stack = new Stack<IEnumerator<UserRole>>();
var e = childrenByParentId[role != null ? role.Id : (int?)null].GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
yield return e.Current;
stack.Push(e);
e = childrenByParentId[e.Current.Id].GetEnumerator();
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
}
}
finally
{
e.Dispose();
while (stack.Count > 0) stack.Pop().Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
更好的方法是(遵循DRY原则)利用How to flatten tree via LINQ? :
public static class TreeUtils
{
public static IEnumerable<T> Expand<T>(
this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector)
{
var stack = new Stack<IEnumerator<T>>();
var e = source.GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
yield return item;
var elements = elementSelector(item);
if (elements == null) continue;
stack.Push(e);
e = elements.GetEnumerator();
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
Run Code Online (Sandbox Code Playgroud)
像这样:
private static IEnumerable<UserRole> FindAllChildren(List<UserRole> allRoles, UserRole role)
{
var childrenByParentId = allRoles.ToLookup(r => r.ParentId);
return childrenByParentId[role != null ? role.Id : (int?)null].Expand(r => childrenByParentId[r.Id]);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2608 次 |
| 最近记录: |