I have data in this fashion:
Parent | Data
---------------
Root | AAA
AAA | BBB
AAA | CCC
AAA | DDD
BBB | EEE
BBB | FFF
I have a simpler solution using TreeView object. If you don't mind the order of the nodes to be difference and using MSCOMCTL.OCX, please use below code.
Requires MSOCOMCTL.OCX to be registered.
Consider this data:
Using a TreeView (adding to a UserForm for visualization, code not shown):
Code to dump the tree data (normal module, use TreeToText):
Option Explicit
Private oTree As TreeView
Private Sub CreateTree()
On Error Resume Next ' <-- To keep running even error occurred
Dim oRng As Range, sParent As String, sChild As String
Set oRng = ThisWorkbook.Worksheets("Sheet1").Range("A2") ' <-- Change here to match your Root cell
Do Until IsEmpty(oRng)
sParent = oRng.Value
sChild = oRng.Offset(0, 1).Value
If InStr(1, sParent, "root", vbTextCompare) = 1 Then
oTree.Nodes.Add Key:=sChild, Text:=sChild
Else
oTree.Nodes.Add Relative:=oTree.Nodes(sParent).Index, Relationship:=tvwChild, Key:=sChild, Text:=sChild
End If
'--[ ERROR HANDLING HERE ]--
' Invalid (Repeating) Child will have the Row number appended
If Err.Number = 0 Then
Set oRng = oRng.Offset(1, 0) ' Move to Next Row
Else
oRng.Offset(0,1).Value = sChild & " (" & oRng.Row & ")"
Err.Clear
End If
Loop
Set oRng = Nothing
End Sub
Sub TreeToText()
Dim oRng As Range, oNode As Node, sPath As String, oTmp As Variant
' Create Tree from Data
Set oTree = New TreeView
CreateTree
' Range to dump Tree Data
Set oRng = ThisWorkbook.Worksheets("Sheet1").Range("D2") ' <-- Change here
For Each oNode In oTree.Nodes
sPath = oNode.FullPath
If InStr(1, sPath, oTree.PathSeparator, vbTextCompare) > 0 Then
oTmp = Split(sPath, oTree.PathSeparator)
oRng.Resize(, UBound(oTmp) + 1).Value = oTmp
Set oRng = oRng.Offset(1, 0)
End If
Next
Set oRng = Nothing
Set oTree = Nothing
End Sub
Output of code (hard code to D2):
If you have a very large data, you better off load the Range to memory first.