excelvba

Excel Dynamic Grouping/Hierarchy Tool With Merged Rows


I commonly use sheets that look like the following:

Example of Excel sheet

That is built as a comparison tool based on exports from another application. Note that the rows are merged 2 at a time.

The number in left-most column is currently being used for conditional formatting to add the coloring, but it also represents the hierarchy that I am trying to group by.

As it currently stands, I go through and manually group the rows so that they can be expanded and collapsed. My goal is to figure out a way to use VBA to do that work for me since these sheets can often be 5,000+ rows.

I've found similar threads that get me close, but I haven't figured out a way to make it work with merged rows like shown, the closest I have been able to get is grouping just the first row but not grabbing both.

Any help is greatly appreciated! Thanks!


Solution

  • I'm not a real user of grouping in Excel, so I might be misunderstanding your use case, but this seemed to work for me on a simple example:

    Sub GroupIt()
        Dim ws As Worksheet, c As Range, grp As Range
        Dim rngLevels As Range, lvl As Long, maxLvl As Long, i As Long
        
        Set ws = ActiveSheet
        ws.Cells.ClearOutline               'clear previous grouping
        Set rngLevels = ws.Range("A2:A33")  'range with the level values
        maxLvl = Application.Max(rngLevels) 'max level value
        Debug.Print maxLvl
        Application.ScreenUpdating = False
        For lvl = maxLvl To 2 Step -1       'loop down from max. level
            Set grp = Nothing
            For Each c In rngLevels.Cells
                If c.MergeArea(1).Value >= lvl Then   'current level or greater?
                    UnionRanges grp, c      'add this row to the current group
                Else
                    CloseGroup grp          'group any collected rows
                End If
            Next c
            CloseGroup grp
        Next lvl
        
    End Sub
    
    'Handle closing out a group of collected cells and
    '   reset `grp` to Nothing
    Sub CloseGroup(ByRef grp As Range)
        If Not grp Is Nothing Then
            Debug.Print "Grouping " & grp.Address
            grp.EntireRow.Group
            Set grp = Nothing
        End If
    End Sub
    
    'Add range `rngToadd` to range `RngTot`
    Sub UnionRanges(rngTot As Range, rngToAdd As Range)
        If rngTot Is Nothing Then
            Set rngTot = rngToAdd
        Else
            Set rngTot = Application.Union(rngTot, rngToAdd)
        End If
    End Sub
    

    Before and after:
    before and after