vb.net LINQ 在树视图中获取最深层次的节点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14141792/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
LINQ to get deepest level nodes in a treeview
提问by John Bustos
Suppose I have a WinForms Treeview that looks as follows:
假设我有一个如下所示的 WinForms Treeview:
Parent1
Child1
Sub-Child1
DeepestNode1
DeepestNode2
DeepestNode3
Sub-Child2
DeepestNode4
DeepestNode5
DeepestNode6
Child2
Sub-Child3
Sub-Child4
Sub-Child5
Sub-Child6
Child3
(no children)
I would like to create a function along the lines of:
我想按照以下方式创建一个函数:
Function GetDeepestChildren(MyNode as Treenode) as List(Of Treenode)
Where, if the results would look like:
如果结果如下所示:
GetDeepestChildren(Parent1) = {DeepestNode1, DeepestNode2, DeepestNode3, DeepestNode4, DeepestNode5, DeepestNode6}
GetDeepestChildren(Sub-Child1) = {DeepestNode1, DeepestNode2, DeepestNode3}
GetDeepestChildren(Child2) = {Sub-Child3, Sub-Child4, Sub-Child5, Sub-Child6}
GetDeepestChildren(Child3) = Empty list
... In other words, always go to the deepest level you can from the node given and return the children - Even if they're split between different parents (as was the case in Parent1).
... 换句话说,总是从给定的节点进入最深的层次并返回子节点 - 即使它们在不同的父节点之间分裂(如 中的情况Parent1)。
I have created a function that will tell me how many levels deeper a node goes that looks like:
我创建了一个函数,它会告诉我一个节点的深度有多少层,如下所示:
Public Function GetDeepestChildNodeLevel(ByVal ParentNode As TreeNode) As Integer
Dim subLevel = ParentNode.Nodes.Cast(Of TreeNode).Select(Function(subNode) GetDeepestChildNodeLevel(subNode))
Return If(subLevel.Count = 0, 0, subLevel.Max() + 1)
End Function
So I know from what level to get the children, what i'm looking for is a function that can do this - Somethign along the lines of:
所以我知道从什么级别得到孩子,我正在寻找的是一个可以做到这一点的功能 - 一些类似的东西:
Function GetDeepestChildren(MyNode as Treenode) as List(Of Treenode)
Return All child nodes where level = GetDeepestChildNodeLevel(MyNode)
End function
I hope this makes sense - Thanks!
我希望这是有道理的 - 谢谢!
采纳答案by dasblinkenlight
In C# you can do it with yield returnor with a recursive lambda. Here is an example of the second approach:
在 C# 中,您可以使用yield return或使用递归 lambda 来完成。以下是第二种方法的示例:
Func<TreeNode,IEnumerable<TreeNode>> getChildren = null;
getChildren = n => {
if (n.Nodes.Count != 0) {
var list = new List<TreeNode>(n.Nodes.Where(c => c.Nodes.Count == 0));
foreach (var c in n.Nodes) {
// Note the recursive call below:
list.AddRange(getChildren(c));
}
return list;
} else {
return new TreeNode[0];
}
};
var res = getChildren(myTree);
回答by Hogan
Here is a version using XML -- the translation should be easy. I used linqPadwhich I recommend for this kind of stuff, you can run this and see it work directly in linkPad
这是一个使用 XML 的版本——翻译应该很容易。我使用了linqPad,我为这类东西推荐了它,你可以运行它并直接在 linkPad 中看到它的工作
WalkDeep(tree,getDeep(tree)) returns:
<DeepestNode1 />
<DeepestNode2 />
<DeepestNode3 />
<DeepestNode4 />
<DeepestNode5 />
<DeepestNode6 />
The C# code is nicer because you can use yield
C# 代码更好,因为您可以使用 yield
VB Code
VB代码
function getDeep( e as XElement) as integer
if (e.HasElements)
return 1 + e.Elements().Select(Function(c) getDeep(c)).Max()
else
return 1
end if
end function
function WalkDeep(root as XElement,find as integer,optional mylevel as integer = 1) as IEnumerable(of XElement)
Dim result As New List(Of XElement)
if find = mylevel
result.Add(root)
else
if root.HasElements
for each c as XElement in root.Elements()
for each r as XElement in WalkDeep(c,find,mylevel+1)
result.Add(r)
next
next
end if
end if
return result
end function
Sub Main
dim tree as XElement = <Parent1>
<Child1>
<Sub-Child1>
<DeepestNode1/>
<DeepestNode2/>
<DeepestNode3/>
</Sub-Child1>
<Sub-Child2>
<DeepestNode4/>
<DeepestNode5/>
<DeepestNode6/>
</Sub-Child2>
</Child1>
<Child2>
<Sub-Child3/>
<Sub-Child4/>
<Sub-Child5/>
<Sub-Child6/>
</Child2>
<Child3 />
</Parent1>
WalkDeep(tree,getDeep(tree)).Select(function(x) x.Name.LocalName).Dump()
End Sub
C# Code:
C# 代码:
int getDeep(XElement e)
{
if (e.HasElements)
return 1 + e.Elements().Select(c => getDeep(c)).Max();
else
return 1;
}
IEnumerable<XElement> WalkDeep(XElement root,int find, int mylevel=1)
{
if (find == mylevel) yield return root;
if (root.HasElements)
{
foreach(XElement c in root.Elements())
{
foreach(XElement r in WalkDeep(c,find,mylevel+1))
yield return r;
}
}
yield break;
}
void Main()
{
XElement tree = XElement.Parse (@"
<Parent1>
<Child1>
<Sub-Child1>
<DeepestNode1/>
<DeepestNode2/>
<DeepestNode3/>
</Sub-Child1>
<Sub-Child2>
<DeepestNode4/>
<DeepestNode5/>
<DeepestNode6/>
</Sub-Child2>
</Child1>
<Child2>
<Sub-Child3/>
<Sub-Child4/>
<Sub-Child5/>
<Sub-Child6/>
</Child2>
<Child3 />
</Parent1>
");
WalkDeep(tree,getDeep(tree)).Dump();
}
回答by John Bustos
This is a VB.Net re-make I created of @dasblinkenlight's solution - It worked perfectly and I'm just putting it here in case anyone in the future needs the solution in VB.
这是我用@dasblinkenlight 的解决方案创建的 VB.Net 重新制作 - 它运行良好,我只是把它放在这里,以防将来有人需要 VB 中的解决方案。
Public Function GetDeepestChildNodes(ByVal ParentNode As TreeNode) As List(Of TreeNode)
Dim RetVal As New List(Of TreeNode)
If ParentNode.Nodes.Count > 0 Then
RetVal = (From nd As TreeNode In ParentNode.Nodes
Where nd.Nodes.Count = 0
Select nd).ToList
For Each nd In ParentNode.Nodes
RetVal.AddRange(GetDeepestChildNodes(nd))
Next
End If
Return RetVal
End Function
Thank you all again for your help!!!
再次感谢大家的帮助!!!
回答by Fredou
it is not linq, since i think in this case it should not be done by linq sorry if it's not what you asked but this work. it is not fullproof but at least you wont get stackoverflow if you get a crazy tree
它不是 linq,因为我认为在这种情况下它不应该由 linq 完成,如果不是你问的而是这项工作,抱歉。它不是完全可靠的,但至少如果你得到一棵疯狂的树,你不会得到 stackoverflow
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim test1 = GetDeepestChildren(TreeView1.Nodes(0))
Dim test2 = GetDeepestChildren(TreeView1.Nodes(0).Nodes(0).Nodes(0))
Dim test3 = GetDeepestChildren(TreeView1.Nodes(0).Nodes(1))
Dim test4 = GetDeepestChildren(TreeView1.Nodes(0).Nodes(2))
End Sub
Private Function GetDeepestChildren(ByVal node As TreeNode) As List(Of TreeNode)
Dim deepestList As New List(Of TreeNode)
If node.Nodes.Count = 0 Then
Return deepestList
End If
Dim nodes As New Stack(Of TreeNode)
For Each n As TreeNode In node.Nodes
nodes.Push(n)
Next
Dim deepest As Integer = 0
Do Until nodes.Count = 0
node = nodes.Pop
If node.Nodes.Count = 0 Then
If deepest < node.Level Then
deepest = node.Level
deepestList.Clear()
deepestList.Add(node)
ElseIf deepest = node.Level Then
deepestList.Add(node)
End If
Else
For Each n As TreeNode In node.Nodes
nodes.Push(n)
Next
End If
Loop
Return deepestList
End Function
回答by gfyans
I'm not familiar with the TreeView control, but is the Level property of the TreeNode any good to you?
我不熟悉 TreeView 控件,但是 TreeNode 的 Level 属性对您有好处吗?
http://msdn.microsoft.com/en-us/library/system.windows.forms.treenode.level.aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.treenode.level.aspx
If you know the deepest level, you could do this:
如果你知道最深层次,你可以这样做:
C#
C#
private List<TreeNode> GetDeepestChildren(int level)
{
return (from p in treeView1.Nodes.Cast<TreeNode>() where p.Level == level select p).ToList();
}
VB
VB
Private Function GetDeepestChildren(level As Integer) As List(Of TreeNode)
Return (From p In treeView1.Nodes.Cast(Of TreeNode)() Where p.Level = levelp).ToList()
End Function
Greg.
格雷格。
回答by JerKimball
This is justa slight modification of @dasblinkenlight 's answer, so don't upvote this!
这只是对@dasblinkenlight 的回答的轻微修改,所以不要点赞!
Just a matter of personal style, but I rather like the recursive call as such:
只是个人风格的问题,但我更喜欢这样的递归调用:
IEnumerable<TreeNode> WalkNodes(TreeNode root)
{
yield return root;
var children = root.Nodes.Cast<TreeNode>();
foreach (var child in children)
{
foreach(var subChild in WalkNodes(child))
{
yield return subChild;
}
}
}
And called via:
并通过以下方式调用:
foreach (var node in treeView.Nodes.Cast<TreeNode>())
{
var walkedFrom = WalkNodes(node);
foreach (var subNode in walkedFrom)
{
Console.WriteLine(subNode.Text);
}
}
回答by Stokedout
Tried a recursive function yet? Not sure in VB.Net but C# would look like
试过递归函数了吗?在 VB.Net 中不确定,但 C# 看起来像
public List<TreeNode> GetDeepestChildren(Treenode MyNode)
{
if (MyNode.Children.Count > 0)
GetDeepestChildren(Treenode MyNode);
else
return MyNode.Children;
}
This hasnt been compiled or tested but the idea is there and should return the deepest children for any given node.
这还没有被编译或测试,但这个想法已经存在并且应该返回任何给定节点的最深子节点。

