Convert Parent-Child into Excel Hierarchy using VBA

aston_007

New Member
Joined
Apr 7, 2023
Messages
9
Office Version
  1. 365
  2. 2013
Platform
  1. Windows
Hi experts!

I'm trying to traverse and convert a Parent|Child file into a separate hierarchy, with a header.
The 'depth' of the Parent|Child relationships is yet unknown, so the output could stretch to many columns on the right.
I have tried coding for just two input columns, with little success as it's very slow and restrictive.

Any help would be much appreciated. Thank you.

Input tab:
ParentChildDescription
EuropeUKUnited Kingdom
EuropeFRFrance
EuropeESSpain
EuropeITItaly
EuropeDEGermany
UKLDNLondon
UKLDSLeeds
UKLIVLiverpool
FRPARParis
FRLYNLyon
FRDIJDijon
FRCALCalais
ESMADMadrid
ESMALMalaga
ESVALValencia
LDNRCHRichmond
LDNCHWChiswick
MADSALSalamanca
MADRETRetiro

Output Tab:
ContinentCountryCountry DescCityCity DescTownTown Desc
Europe
UKUnited Kingdom
LDNLondon
RCHRichmond
CHWChiswick
LDSLeeds
LIVLiverpool
FRFrance
PARParis
LYNLyon
DIJDijon
CALCalais
ESSpain
MADMadrid
SALSalamanca
RETRetiro
MALMalaga
VALValencia
 

Attachments

  • VBA.jpg
    VBA.jpg
    111.8 KB · Views: 20

Excel Facts

Show numbers in thousands?
Use a custom number format of #,##0,K. Each comma after the final 0 will divide the displayed number by another thousand
Consider:

VBA Code:
Sub Hierarchy()
Dim InputCell As Range, OutputCell As Range, d As Variant
Dim t() As Variant, ts As Variant, TopLevel As String
Dim i As Long, r As Long, c As Long, l2 As String, Loc As Long

    Set InputCell = Sheets("Sheet1").Range("A2")
    Set OutputCell = Sheets("Sheet1").Range("F2")
    
    d = InputCell.Resize(InputCell.End(xlDown).Row - InputCell.Row + 1, 3).Value
    ReDim t(1 To UBound(d), 0 To 10)
    
    TopLevel = d(1, 1)
    For i = 1 To UBound(d)
        str1 = d(i, 2) & "|"
        l2 = d(i, 2)
        While l2 <> TopLevel
            With WorksheetFunction
                l2 = .XLookup(l2, .Index(d, 0, 2), .Index(d, 0, 1), 0)
            End With
            str1 = l2 & "|" & str1
        Wend
        c = 1
        While str1 <> ""
            Loc = InStr(str1, "|")
            t(i, c) = Left(str1, Loc - 1)
            str1 = Mid(str1, Loc + 1)
            c = c + 1
        Wend
        While c < 11
            t(i, c) = Chr(1)
            c = c + 1
        Wend
        t(i, 0) = d(i, 3)
    Next i
    
    ts = WorksheetFunction.Sort(t, Array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11), Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1))
    Application.ScreenUpdating = False

    OutputCell = TopLevel
    For r = 1 To UBound(ts)
        For i = 2 To 10
            If ts(r, i) = Chr(1) Then Exit For
        Next i
        c = i - 3
        OutputCell.Offset(r, c * 2) = ts(r, c + 2)
        OutputCell.Offset(r, c * 2 + 1) = ts(r, 1)
    Next r

    Application.ScreenUpdating = True        
End Sub

This changes the A2 range to the F2 table:

Book2
ABCDEFGHIJKLMN
1ParentChildDescription
2EuropeUKUnited KingdomEurope
3EuropeFRFranceDEGermany
4EuropeESSpainESSpain
5EuropeITItalyMADMadrid
6EuropeDEGermanyRETRetiro
7UKLDNLondonSALSalamanca
8UKLDSLeedsMALMalaga
9UKLIVLiverpoolVALValencia
10FRPARParisFRFrance
11FRLYNLyonCALCalais
12FRDIJDijonDIJDijon
13FRCALCalaisLYNLyon
14ESMADMadridPARParis
15ESMALMalagaITItaly
16ESVALValenciaUKUnited Kingdom
17LDNRCHRichmondLDNLondon
18LDNCHWChiswickCHWChiswick
19MADSALSalamancaRCHRichmond
20MADRETRetiroLDSLeeds
21LIVLiverpool
22
23
24
Sheet1


Numerous caveats for this:

1) The top left item (Europe) is considered to be the root.
2) Every code in column 2 must be unique. There can't be a Springfield in both England and France for example, unless it's something like SPRE and SPRF.
3) This routine will handle up to 10 levels of dependency. That's easily changed if you want, even to an arbitrary amount.
4) I wrote this with 2 Excel 365 functions (Sort and XMATCH) which aren't available in Excel 2013.

However, it should work for you. Let me know what you think.
 
Upvote 0
Solution
Hi Eric.

That's amazing! This is just what I needed.

Apologies for the late reply as it was getting 'stuck' half way through its operation. I realised that some of the child values are numbers, so I'll need to convert these numbers to text before running or better still, cater for these numbers within the VBA script.

Thanks again Eric.

Mark
 
Upvote 0
I might have a go with a possible recursive solution later once I get home to my pc
 
Upvote 0
Here a solution with a treeview (in a userform)

This is the code:

VBA Code:
Private Sub UserForm_Initialize()
 Dim dic As Object, ar, j As Long
 
 ar = Sheets(1).Cells(1).CurrentRegion
 Set dic = CreateObject("scripting.dictionary")
 
 For j = 2 To UBound(ar)
    If Not dic.Exists(ar(j, 1)) Then
       dic(ar(j, 1)) = Empty
       dic(ar(j, 2)) = Empty
       TreeView1.Nodes.Add , , ar(j, 1), ar(j, 1)
       TreeView1.Nodes.Add ar(j, 1), 4, ar(j, 2), ar(j, 2) & "-" & ar(j, 3)
    Else
       TreeView1.Nodes.Add ar(j, 1), 4, ar(j, 2), ar(j, 2) & "-" & ar(j, 3)
       dic(ar(j, 2)) = Empty
    End If
 Next
End Sub


1717405240156.png
 
Upvote 0
Here a solution with a treeview (in a userform)

This is the code:

VBA Code:
Private Sub UserForm_Initialize()
 Dim dic As Object, ar, j As Long
 
 ar = Sheets(1).Cells(1).CurrentRegion
 Set dic = CreateObject("scripting.dictionary")
 
 For j = 2 To UBound(ar)
    If Not dic.Exists(ar(j, 1)) Then
       dic(ar(j, 1)) = Empty
       dic(ar(j, 2)) = Empty
       TreeView1.Nodes.Add , , ar(j, 1), ar(j, 1)
       TreeView1.Nodes.Add ar(j, 1), 4, ar(j, 2), ar(j, 2) & "-" & ar(j, 3)
    Else
       TreeView1.Nodes.Add ar(j, 1), 4, ar(j, 2), ar(j, 2) & "-" & ar(j, 3)
       dic(ar(j, 2)) = Empty
    End If
 Next
End Sub


View attachment 112185

That looks neat!

I'll need to scrub up on my control skills to test this out end to end. Thank you.
 
  • Like
Reactions: JEC
Upvote 0
a formula solution for your reference:
结构转换小题-REDUCE双循环+递归.xlsx
ABCDEFGHIJKL
1ParentChildDescription234Europe
2EuropeUKUnitedKingdomDEGermany
3EuropeFRFranceESSpain
4EuropeESSpainMADMadrid
5EuropeITItalyRETRetiro
6EuropeDEGermanySALSalamanca
7UKLDNLondonMALMalaga
8UKLDSLeedsVALValencia
9UKLIVLiverpoolFRFrance
10FRPARParisCALCalais
11FRLYNLyonDIJDijon
12FRDIJDijonLYNLyon
13FRCALCalaisPARParis
14ESMADMadridITItaly
15ESMALMalagaUKUnitedKingdom
16ESVALValenciaLDNLondon
17LDNRCHRichmondCHWChiswick
18LDNCHWChiswickRCHRichmond
19MADSALSalamancaLDSLeeds
20MADRETRetiroLIVLiverpool
21AsiaChinaBeijingAsia
22AsiaJapanTokyoChinaBeijing
23JapanTokyo
24
递归 (2)
Cell Formulas
RangeFormula
D1D1=LEN(FORMULATEXT(E1))
E1:K23E1=LET(A,A2:A22,B,B2:C22,f,LAMBDA(f,m,DROP(REDUCE(0,SEQUENCE(ROWS(m)),LAMBDA(x,y,LET(u,INDEX(m,y,),s,SORT(FILTER(B,A=@TAKE(u,-2),0)),IFNA(VSTACK(x,IF(@s=0,u,HSTACK(u,VSTACK("",f(f,s))))),"")))),1)),f(f,UNIQUE(FILTER(A,COUNTIF(B,A)=0))))
Dynamic array formulas.

1717568480039.png
 
Upvote 0

Forum statistics

Threads
1,224,814
Messages
6,181,120
Members
453,021
Latest member
Justyna P

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top