代码之家  ›  专栏  ›  技术社区  ›  Michael Galos

在Excel中构建数据的树状表示?

  •  7
  • Michael Galos  · 技术社区  · 15 年前

    我有一堆这样的原始数据:

    Parent  |  Data
    ---------------
    Root    | AAA
    AAA     | BBB
    AAA     | CCC
    AAA     | DDD
    BBB     | EEE
    BBB     | FFF
    CCC     | GGG
    DDD     | HHH
    

    这需要转换成一种树状的时尚。 这基本上需要在excel电子表格中结束。 如何将上述数据转换为以下内容:

    AAA |      |
        | BBB  |
        |      | EEE
        |      | FFF
        | CCC  |
        |      | GGG
        | DDD  |
        |      | HHH
    

    有没有简单的方法只使用VBA就可以做到这一点?

    2 回复  |  直到 15 年前
        1
  •  13
  •   Christian Payne Larry Baltz    15 年前

    我相信您可以整理一下,但这将对您提供的数据集起作用。

    开始之前,需要定义两个名称(Insert/Name/define)。“数据”是数据集的范围,“目的地”是您希望树到达的位置。

    Sub MakeTree()
    
        Dim r As Integer
        ' Iterate through the range, looking for the Root
        For r = 1 To Range("Data").Rows.Count
            If Range("Data").Cells(r, 1) = "Root" Then
                DrawNode Range("Data").Cells(r, 2), 0, 0
            End If
        Next
    
    End Sub
    
    Sub DrawNode(ByRef header As String, ByRef row As Integer, ByRef depth As Integer)
    'The DrawNode routine draws the current node, and all child nodes.
    ' First we draw the header text:
        Cells(Range("Destination").row + row, Range("Destination").Column + depth) = header
    
        Dim r As Integer
        'Then loop through, looking for instances of that text
        For r = 1 To Range("Data").Rows.Count
            If Range("Data").Cells(r, 1) = header Then
            'Bang!  We've found one!  Then call itself to see if there are any child nodes
                row = row + 1
                DrawNode Range("Data").Cells(r, 2), row, depth + 1
            End If
        Next
    End Sub
    
        2
  •  0
  •   Vincent Tang    7 年前

    我今天不得不查找这个解决方案,我在别处找到了它,以防有人还在寻找这个答案

    指定要作为“输入”的工作表

    输出表为“水平结构”

    形式正在改变 parent | child ,因此,如果您的数据是向后的,则只需交换列(如果它是最顶端的节点),然后放入 root parent .

    这样,A、B列中的每个单元格都有一些值

    运行excelvba

    资料来源: https://sites.google.com/a/madrocketscientist.com/jerrybeaucaires-excelassistant/text-functions/cascading-tree

    Option Explicit
    
    Sub TreeStructure()
    'JBeaucaire  3/6/2010, 10/25/2011
    'Create a flow tree from a two-column accountability table
    Dim LR As Long, NR As Long, i As Long, Rws As Long
    Dim TopRng As Range, TopR As Range, cell As Range
    Dim wsTree As Worksheet, wsData As Worksheet
    Application.ScreenUpdating = False
    
    'Find top level value(s)
    Set wsData = Sheets("Input")
      'create a unique list of column A values in column M
        wsData.Range("A:A").AdvancedFilter Action:=xlFilterCopy, _
             CopyToRange:=wsData.Range("M1"), Unique:=True
    
      'Find the ONE value in column M that reports to no one, the person at the top
        wsData.Range("N2", wsData.Range("M" & Rows.Count).End(xlUp) _
            .Offset(0, 1)).FormulaR1C1 = "=IF(COUNTIF(C2,RC13)=0,1,"""")"
        Set TopRng = wsData.Columns("N:N").SpecialCells(xlCellTypeFormulas, 1).Offset(0, -1)
      'last row of persons listed in data table
        LR = wsData.Range("A" & wsData.Rows.Count).End(xlUp).Row
    
    'Setup table
        Set wsTree = Sheets("LEVEL STRUCTURE")
        With wsTree
            .Cells.Clear    'clear prior output
            NR = 3          'next row to start entering names
    
    'Parse each run from the top level
        For Each TopR In TopRng         'loop through each unique column A name
            .Range("B" & NR) = TopR
            Set cell = .Cells(NR, .Columns.Count).End(xlToLeft)
    
            Do Until cell.Column = 1
              'filter data to show current leader only
                wsData.Range("A:A").AutoFilter Field:=1, Criteria1:=cell
            'see how many rows this person has in the table
                LR = wsData.Range("A" & Rows.Count).End(xlUp).Row
                If LR > 1 Then
                  'count how many people report to this person
                    Rws = Application.WorksheetFunction.Subtotal(103, wsData.Range("B:B")) - 1
                  'insert that many blank rows below their name and insert the names
                    cell.Offset(1, 1).Resize(Rws).EntireRow.Insert xlShiftDown
                    wsData.Range("B2:B" & LR).Copy cell.Offset(1, 1)
                  'add a left border if this is the start of a new "group"
                    If .Cells(.Rows.Count, cell.Column + 1).End(xlUp).Address _
                        <> cell.Offset(1, 1).Address Then _
                           .Range(cell.Offset(1, 1), cell.Offset(1, 1).End(xlDown)) _
                              .Borders(xlEdgeLeft).Weight = xlThick
                End If
    
                NR = NR + 1     'increment to the next row to enter the next top leader name
                Set cell = .Cells(NR, .Columns.Count).End(xlToLeft)
            Loop
        Next TopR
    
      'find the last used column
        i = .Cells.Find("*", .Cells(.Rows.Count, .Columns.Count), _
            SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
      'format the used data range
        With Union(.Range(.[B1], .Cells(1, i)), .Range("B:BB").SpecialCells(xlCellTypeConstants, 23))
            .Interior.ColorIndex = 5
            .Font.ColorIndex = 2
            .Font.Bold = True
            .HorizontalAlignment = xlCenter
        End With
        .Range("B1").Interior.ColorIndex = 53
        .Range("B1").Value = "LEVEL 1"
        .Range("B1").AutoFill Destination:=.Range("B1", .Cells(1, i)), Type:=xlFillDefault
    End With
    
    wsData.AutoFilterMode = False
    wsData.Range("M:N").ClearContents
    wsTree.Activate
    Application.ScreenUpdating = True
    End Sub