我有这样的表层次结构列表:
ID ParentID
1 0
2 7
3 1
4 5
5 1
6 2
7 1
8 6
9 0
10 9
我希望输出到 listTtem 如果子lvl1添加|___
然后+值,如果子lvl 2添加<space>
然后|___
然后+值< / p>
输出:
1
|___ 3
|___ 5
|___ 4
|___ 7
|___ 2
|___ 6
|___ 8
|___ 11
9
|___ 10
我做了什么:
public class MyClass
{
public List<MyClass> Children = new List<MyClass>();
public string ID { get; set; }
public string ParentID { get; set; }
public string Name { get; set; }
}
// GET: Reporting
public ActionResult Index()
{
List<MyClass> ofitems = new List<MyClass>();
var dbs = db.ORG_FUNCTION.Select(pk => new { pk.FUNCTION_ID, pk.FUNCTION_PARENT_ID, pk.NAME });
foreach (var s in dbs)
{
ofitems.Add(new MyClass { ID = s.FUNCTION_ID.ToString(), ParentID = s.FUNCTION_PARENT_ID.ToString(), Name = s.NAME });
}
Action<MyClass> SetChildren = null;
SetChildren = parent =>
{
parent.Children = ofitems
.Where(childItem => childItem.ParentID == parent.ID)
.ToList();
//Recursively call the SetChildren method for each child.
parent.Children
.ForEach(SetChildren);
};
//ViewBag.list = ????;
return View();
}
但它只显示相同的输出。如何通过父子获得不同的输出
答案 0 :(得分:1)
您需要递归遍历树以正确输出它
你的算法确实使用递归,但它只填充Children
属性,甚至可以线性完成:
var byNodeId = ofitems.ToDictionary(x => x.ID, x => x);
foreach (var node in ofitems)
{
// add current node to its parent's Children
byNodeId[node.ParentID].Children.Add(node);
}
之所以重要,是因为您的算法需要O(n*n)
次操作来填充Children
,这比{1}}更糟糕。
即使在填写n
之后,您仍然需要通过树DFS (Depth-First Search) - 可以使用Children
或递归来完成。
这就是递归方式的样子:
Queue
结果:
您的控制器可能如下所示:
public static class TreeFormatter
{
private static string FormatTreeItem(MyClass item, int depth)
{
if (depth == 0)
return $"{item.ID}"; // you can use Name in return
return $"{new string(' ', (depth - 1) * 8)}|___ {item.ID}"; // 8 spaces per level
}
private static void FormatSubtree(StringBuilder sb, List<MyClass> items, string current, int depth)
{
foreach (var child in items.Where(x => x.ParentID == current)) // perhaps .OrderBy?
{
sb.AppendLine(FormatTreeItem(child, depth));
FormatSubtree(sb, items, child.ID, depth + 1);
}
}
public static string Format(List<MyClass> items)
{
var sb = new StringBuilder();
FormatSubtree(sb, items, "0", 0); // "0" = root
return sb.ToString();
}
}
此代码中有许多地方可以改进它,它只是显示了这个想法。
答案 1 :(得分:0)
构建MyClass
树很容易。
试试这个:
ILookup<int, int> lookup = source.ToLookup(x => x.ParentID, x => x.ID);
Func<int, List<MyClass>> build = null;
build = pid =>
lookup[pid]
.Select(id => new MyClass()
{
Children = build(id),
ID = id,
ParentID = pid
})
.ToList();
List<MyClass> ofitems = build(0);
如果您从这些数据开始:
var source = new[]
{
new { ID = 1, ParentID = 0 },
new { ID = 2, ParentID = 7 },
new { ID = 3, ParentID = 1 },
new { ID = 4, ParentID = 5 },
new { ID = 5, ParentID = 1 },
new { ID = 6, ParentID = 2 },
new { ID = 7, ParentID = 1 },
new { ID = 8, ParentID = 6 },
new { ID = 9, ParentID = 0 },
new { ID = 10, ParentID = 9 },
};
然后你得到这个结果:
我确实将MyClass
的定义更改为使用int
作为ID类型而不是字符串,但它也适用于字符串。
输出也相当容易。
试试这个:
string divider = "|___";
Func<IEnumerable<MyClass>, int, IEnumerable<string>> output = null;
output = (items, n) =>
items
.SelectMany(item =>
new []
{
"".PadLeft(
divider.Length * (n - 1 > 0 ? n - 1 : 0))
+ (n > 0 ? divider : "")
+ item.ID
}.Concat(output(item.Children, n + 1)));
然后用output(ofitems, 0)
得到这个:
1 |___3 |___5 |___4 |___7 |___2 |___6 |___8 9 |___10