无需递归将 Treeview 节点集合展平为列表
Flatten Treeview Nodes collection to List without recursion
希望这不是一个重复的问题。我查看并发现了类似的问题,但在这种情况下还不够。
我有很多树视图控件,并且由于各种原因可以递归遍历节点。
但是,我经常需要遍历节点,就好像它们在列表中一样。
我想创建一个函数,从 Nodes 集合中创建一个 Generic.List(of TreeNode)
, 没有递归 如果可能的话。
(不加递归纯粹是为了练习不加递归做的-我理解可能 不可能)
此函数可以在大规模解决方案中重复使用,从而节省大量时间,其中编码人员可以使用简单的 For Each
范例来遍历节点。
我见过一种使用 C# 'flatten' Nodes 集合的技术,它使用 LINQ 和递归,但我不确定语法是否可以完全转换为 VB.NET。因此,如果有任何聪明的 VB 函数可以帮助我完成这项任务 - 将会非常有帮助。
关于 SO 有很多类似的问题和非常有用的答案,比如这个:
Enumerating Collections that are not inherently IEnumerable?
...使用某些算法突出显示非常深的树中的堆栈溢出错误。我希望不使用递归的方法不会出现 Stack overflow 错误 - 但是,我已经准备好它可能又长又笨又慢。
我也准备好回答“没有递归就不可能做到这一点”。但是,我想借助 SO(本论坛)
的力量来确认或否认这种说法
有可能,而且一点也不难....
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TreeView1.ExpandAll()
For Each TN As TreeNode In TreeView1.NodesToListWithoutRecursionBecauseWhyNot(TraverseType.BreadthFirst)
Debug.Print(TN.Text)
Next
End Sub
End Class
Public Module Extensions
Public Enum TraverseType
BreadthFirst
DepthFirst
End Enum
<Runtime.CompilerServices.Extension()> _
Public Function NodesToListWithoutRecursionBecauseWhyNot(ByVal TV As TreeView, Optional ByVal Traverse As TraverseType = TraverseType.DepthFirst) As List(Of TreeNode)
Dim nodes As New List(Of TreeNode)
Select Case Traverse
Case TraverseType.BreadthFirst
Dim Q As New Queue(Of TreeNode)
For Each TN As TreeNode In TV.Nodes
Q.Enqueue(TN)
Next
While Q.Count > 0
Dim TN As TreeNode = Q.Dequeue
nodes.Add(TN)
For Each subTN As TreeNode In TN.Nodes
Q.Enqueue(subTN)
Next
End While
Case TraverseType.DepthFirst
Dim L As New List(Of TreeNode)
For Each TN As TreeNode In TV.Nodes
L.Add(TN)
Next
While L.Count > 0
Dim TN As TreeNode = L.Item(0)
L.RemoveAt(0)
nodes.Add(TN)
For i As Integer = TN.Nodes.Count - 1 To 0 Step -1
L.Insert(0, TN.Nodes(i))
Next
End While
End Select
Return nodes
End Function
End Module
只需将节点添加到列表中,但同时保留您处理的最后一个节点的位置。当一个节点的直接子节点被添加到列表中时,该节点被认为是进程。
Public Function GetAllNodes(ByVal topNode As TreeNode)
Dim allNodes As New List(Of TreeNode)
Dim lastProcessPosition As Integer = 0
allNodes.Add(topNode)
Do While lastProcessPosition < allNodes.Count
allNodes.AddRange(allNodes(lastProcessPosition).Nodes)
lastProcessPosition += 1
Loop
Return allNodes
End Function
如果您没有顶级节点,则只需将参数替换为开始的节点列表。
Public Function GetAllNodes(ByVal topNodes As TreeNodeCollection)
Dim allNodes As New List(Of TreeNode)
Dim lastProcessPosition As Integer = 0
allNodes.AddRange(topNodes)
Do While lastProcessPosition < allNodes.Count
allNodes.AddRange(allNodes(lastProcessPosition).Nodes)
lastProcessPosition += 1
Loop
Return allNodes
End Function
我不确定在使用之前是否必须在节点 属性 上检查 Nothing。
注意:我能够删除这个 for 循环并将其替换为 AddRange
'For Each node As TreeNode In allNodes(lastProcessPosition).Nodes
' allNodes.Add(node)
'Next
希望这不是一个重复的问题。我查看并发现了类似的问题,但在这种情况下还不够。
我有很多树视图控件,并且由于各种原因可以递归遍历节点。
但是,我经常需要遍历节点,就好像它们在列表中一样。
我想创建一个函数,从 Nodes 集合中创建一个 Generic.List(of TreeNode)
, 没有递归 如果可能的话。
(不加递归纯粹是为了练习不加递归做的-我理解可能 不可能)
此函数可以在大规模解决方案中重复使用,从而节省大量时间,其中编码人员可以使用简单的 For Each
范例来遍历节点。
我见过一种使用 C# 'flatten' Nodes 集合的技术,它使用 LINQ 和递归,但我不确定语法是否可以完全转换为 VB.NET。因此,如果有任何聪明的 VB 函数可以帮助我完成这项任务 - 将会非常有帮助。
关于 SO 有很多类似的问题和非常有用的答案,比如这个: Enumerating Collections that are not inherently IEnumerable? ...使用某些算法突出显示非常深的树中的堆栈溢出错误。我希望不使用递归的方法不会出现 Stack overflow 错误 - 但是,我已经准备好它可能又长又笨又慢。
我也准备好回答“没有递归就不可能做到这一点”。但是,我想借助 SO(本论坛)
的力量来确认或否认这种说法有可能,而且一点也不难....
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TreeView1.ExpandAll()
For Each TN As TreeNode In TreeView1.NodesToListWithoutRecursionBecauseWhyNot(TraverseType.BreadthFirst)
Debug.Print(TN.Text)
Next
End Sub
End Class
Public Module Extensions
Public Enum TraverseType
BreadthFirst
DepthFirst
End Enum
<Runtime.CompilerServices.Extension()> _
Public Function NodesToListWithoutRecursionBecauseWhyNot(ByVal TV As TreeView, Optional ByVal Traverse As TraverseType = TraverseType.DepthFirst) As List(Of TreeNode)
Dim nodes As New List(Of TreeNode)
Select Case Traverse
Case TraverseType.BreadthFirst
Dim Q As New Queue(Of TreeNode)
For Each TN As TreeNode In TV.Nodes
Q.Enqueue(TN)
Next
While Q.Count > 0
Dim TN As TreeNode = Q.Dequeue
nodes.Add(TN)
For Each subTN As TreeNode In TN.Nodes
Q.Enqueue(subTN)
Next
End While
Case TraverseType.DepthFirst
Dim L As New List(Of TreeNode)
For Each TN As TreeNode In TV.Nodes
L.Add(TN)
Next
While L.Count > 0
Dim TN As TreeNode = L.Item(0)
L.RemoveAt(0)
nodes.Add(TN)
For i As Integer = TN.Nodes.Count - 1 To 0 Step -1
L.Insert(0, TN.Nodes(i))
Next
End While
End Select
Return nodes
End Function
End Module
只需将节点添加到列表中,但同时保留您处理的最后一个节点的位置。当一个节点的直接子节点被添加到列表中时,该节点被认为是进程。
Public Function GetAllNodes(ByVal topNode As TreeNode)
Dim allNodes As New List(Of TreeNode)
Dim lastProcessPosition As Integer = 0
allNodes.Add(topNode)
Do While lastProcessPosition < allNodes.Count
allNodes.AddRange(allNodes(lastProcessPosition).Nodes)
lastProcessPosition += 1
Loop
Return allNodes
End Function
如果您没有顶级节点,则只需将参数替换为开始的节点列表。
Public Function GetAllNodes(ByVal topNodes As TreeNodeCollection)
Dim allNodes As New List(Of TreeNode)
Dim lastProcessPosition As Integer = 0
allNodes.AddRange(topNodes)
Do While lastProcessPosition < allNodes.Count
allNodes.AddRange(allNodes(lastProcessPosition).Nodes)
lastProcessPosition += 1
Loop
Return allNodes
End Function
我不确定在使用之前是否必须在节点 属性 上检查 Nothing。
注意:我能够删除这个 for 循环并将其替换为 AddRange
'For Each node As TreeNode In allNodes(lastProcessPosition).Nodes
' allNodes.Add(node)
'Next