假设我有一个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)
我想按照以下方式创建一个函数:
Function GetDeepestChildren(MyNode as Treenode) as List(Of Treenode)
如果结果如下:
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
...换句话说,总是从给定的节点进入最深层次并返回孩子 - 即使他们在不同的父母之间分开(如Parent1
中的情况)。< / p>
我已经创建了一个函数,它会告诉我节点的深度级别是多少:
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
所以我知道从什么程度上得到孩子,我正在寻找的是一个可以做到这一点的功能 - Somethign的行:
Function GetDeepestChildren(MyNode as Treenode) as List(Of Treenode)
Return All child nodes where level = GetDeepestChildNodeLevel(MyNode)
End function
我希望这是有道理的 - 谢谢!
答案 0 :(得分:3)
在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);
答案 1 :(得分:1)
这是一个使用XML的版本 - 翻译应该很容易。我使用linqPad我推荐这种东西,你可以运行它,直接在linkPad中看到它
WalkDeep(tree,getDeep(tree)) returns:
<DeepestNode1 />
<DeepestNode2 />
<DeepestNode3 />
<DeepestNode4 />
<DeepestNode5 />
<DeepestNode6 />
C#代码更好,因为你可以使用yield
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#代码:
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();
}
答案 2 :(得分:1)
这是一个VB.Net重新制作我创建的@dasblinkenlight的解决方案 - 它工作得很好,我只是把它放在这里以防将来有人需要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
再次感谢大家的帮助!!!
答案 3 :(得分:0)
试过一个递归函数了吗?在VB.Net中不确定,但C#看起来像
public List<TreeNode> GetDeepestChildren(Treenode MyNode)
{
if (MyNode.Children.Count > 0)
GetDeepestChildren(Treenode MyNode);
else
return MyNode.Children;
}
这还没有被编译或测试,但是这个想法就在那里,并且应该为任何给定节点返回最深的子节点。
答案 4 :(得分:0)
我不熟悉TreeView控件,但是TreeNode的Level属性对你有什么好处?
http://msdn.microsoft.com/en-us/library/system.windows.forms.treenode.level.aspx
如果你知道最深层次,你可以这样做:
C#
private List<TreeNode> GetDeepestChildren(int level)
{
return (from p in treeView1.Nodes.Cast<TreeNode>() where p.Level == level select p).ToList();
}
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
格雷格。
答案 5 :(得分:0)
这是只是对@dasblinkenlight的回答略有修改,所以不要赞成这个!
只是个人风格的问题,但我更喜欢这样的递归调用:
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;
}
}
}
并通过以下方式致电:
foreach (var node in treeView.Nodes.Cast<TreeNode>())
{
var walkedFrom = WalkNodes(node);
foreach (var subNode in walkedFrom)
{
Console.WriteLine(subNode.Text);
}
}
答案 6 :(得分:0)
它不是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