ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 4067|回复: 7

[求助] 如何按层级数将数据自动分组

[复制链接]

TA的精华主题

TA的得分主题

发表于 2018-4-23 09:23 | 显示全部楼层 |阅读模式
求教一个问题:我的数据是按照比较规范的格式进行分级排列(如A列),我现在可以使用填加辅助列的办法(如C列)将这些数据自动分组。有没有办法可以参照层级数(如D列)将这些数据自动分组呢?
多谢各位帮忙~

按级别自动分组.rar

8.17 KB, 下载次数: 51

TA的精华主题

TA的得分主题

发表于 2018-4-23 09:56 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
Option Explicit

Sub test()
  Dim i, j, arr, flag
  With Sheets("sheet1")
    arr = .Range("a1:a" & .Cells(Rows.Count, "a").End(xlUp).Row + 1)
    ReDim brr(1 To UBound(arr, 1), 1 To 1)
    For i = 2 To UBound(arr, 1) - 1
      flag = False
      For j = i + 1 To UBound(arr, 1)
        If InStr(arr(j, 1), arr(i, 1)) = 1 Then flag = True
        If InStr(arr(j, 1), arr(i, 1)) = 0 Then
          If flag Then brr(i, 1) = i + 1 & "->" & j - 1
          Exit For
        End If
    Next j, i
    .[e1].Resize(UBound(brr, 1)) = brr
  End With
End Sub

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-4-23 10:54 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助

多谢!我去学习一下!

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-5-2 16:37 | 显示全部楼层

您好~由于出差一直没办法仔细研究,我今天才发现一个问题:虽然可以在E列生成级别的代号,但是我把原来的辅助列(即用公式表达分组)删除以后,自动分级显示也就不好使了,这没达到我的初衷,我是想按“层级”列实现自动分级,麻烦您再看看怎么回事,多谢~

按级别自动分组_新.rar

16.95 KB, 下载次数: 39

TA的精华主题

TA的得分主题

发表于 2018-5-28 11:34 | 显示全部楼层
qymjessy 发表于 2018-5-2 16:37
您好~由于出差一直没办法仔细研究,我今天才发现一个问题:虽然可以在E列生成级别的代号,但是我把原来的 ...
  1. '===============================================================================
  2.                              '堆栈在树形结构中使用的实例
  3. '-------------------------------------------------------------------------------
  4. '本实例实现一下功能:
  5.           '(1) 按树形结构设置Excel的数据分组及分级显示
  6.           '(2) 使用方框与连接线绘制树形,类似TreeView效果
  7. '-------------------------------------------------------------------------------
  8.       '原始数据中,有全部数形结构数据,各节点可有重复的编号、能指示节点所在级数的符号、节点的名称、
  9. '-------------------------------------------------------------------------------
  10.       '本代码采用字典对象模拟堆栈,对原始数据循环扫描完成绘制树形图,
  11.   '可学习到堆栈、字典对象、结构图绘制、数据分组分级显示内容
  12.      '本实例可应用于材料列表(BOM)的统计、公司结构绘制等多种实践。
  13. '===============================================================================

  14. Const TR_LEVEL_MARK = "."          '分级标记符
  15. Const TR_COL_LEVEL = "A"             '分级标记列
  16. Const TR_COL_INDEX = "B"            '物料编码列
  17. Const TR_COL_NAME = "B" '"C"            '物料名称列
  18. Const TR_COL_TREE_START = "F"    '树形图开始列
  19. Const TR_ROW_HEIGHT = 20          '行高
  20. Const TR_COL_LINE_WIDTH = 3      '树形线宽
  21. Const TR_COL_BOX_MARGIN = 2    '树形框边缘

  22. Sub CalculationAndDrawTree()
  23.     Dim iMaxRow&, i&, j&, dic, dic_x, aKeys, iLevelLast%, iLevelNow%
  24.     Undo_All     '全部恢复
  25.     Application.ScreenUpdating = False
  26.     iMaxRow = Cells(65536, 1).End(xlUp).Row     '最大行号
  27.     Rows("1:" & iMaxRow).RowHeight = TR_ROW_HEIGHT     '设置行高
  28.     iLevelLast = 0     '初始前一节点的级数
  29.     Set dic = CreateObject("Scripting.Dictionary")    '设置字典对象以模拟堆栈,Key为行号,Item为对应的级数。
  30.     Set dic_x = CreateObject("Scripting.Dictionary")    '设置字典对象,Key为物料编码,Item为对应的个数。目的是为处理物料编码有重复的情况
  31.     For i = 2 To iMaxRow + 1  '从数据起始行开始始到数据结尾行加一为止循环,多一行以收尾堆栈内最后剩余的节点
  32.         dic_x(Range(TR_COL_INDEX & i).Value) = dic_x(Range(TR_COL_INDEX & i).Value) + 1 '处理物料编码有重复的情况,进行计数
  33.         If dic_x(Range(TR_COL_INDEX & i).Value) = 1 Then  '当物料编码第一次出现时
  34.           ssName = Cells(i, TR_COL_INDEX).Text '节点框名称==>物料编码
  35.         Else
  36.           ssName = Cells(i, TR_COL_INDEX).Text & "_" & dic_x(Range(TR_COL_INDEX & i).Value) '节点框名称+序号
  37.         End If
  38.         If i = iMaxRow + 1 Then '当等于最大行+1时
  39.             iLevelNow = 0  '级数为0
  40.         Else
  41.             iLevelNow = UBound(Split(Range(TR_COL_LEVEL & i), TR_LEVEL_MARK)) + 1 '获得当前节点级数,此例用A列分级标记符(".")数量判断
  42.             Rows(i).OutlineLevel = iLevelNow   '设置当前行的大纲级数
  43.         End If
  44.         If dic.Exists(i - 1) Then  '如果前一节点在堆栈内,且前一节点级数同当前节点,则将前一节点从堆栈内删除
  45.             If dic(i - 1) = iLevelNow Then dic.Remove i - 1
  46.         End If
  47.             '判断当前节点和前一节点的级数关系
  48.             If iLevelNow > iLevelLast Then   '当前节点级数大于前一节点,将当前节点压入堆栈
  49.                 dic(i) = iLevelNow
  50.                 If i > 2 Then dic(i - 1) = UBound(Split(Range(TR_COL_LEVEL & i - 1), TR_LEVEL_MARK)) + 1 '目的是处理同一级中层级数混合时(如:++,++,+++)的情况  画树形线
  51.             ElseIf iLevelNow < iLevelLast Then '当前节点级数小于前一节点,将堆栈内大于等于当前节点级数的项有堆栈顶开始逐一弹出
  52.                 aKeys = dic.keys '获得堆栈内记录的行号赋值给数组
  53.                 For j = UBound(aKeys) To LBound(aKeys) Step -1  '由堆栈顶开始向堆栈底循环
  54.                     If dic(aKeys(j)) < iLevelNow Then Exit For  '当循环至记录的级数小于当前节点级数则退出循环
  55.                     dic.Remove aKeys(j)  '删除堆栈顶部项目
  56.                 Next
  57.                 dic(i) = iLevelNow  '将当前节点压入堆栈
  58.             End If
  59.             iLevelLast = iLevelNow  '记录当前节点为前一节点,供下一个循环使用
  60.             '绘制当前节点框,并与父节点绘制连接线
  61.             If i < iMaxRow + 1 Then DrawLevelBoxAndLine i, iLevelNow, dic, dic_x, ssName
  62.     Next i
  63.     '清空字典项并重置对象
  64.     dic.RemoveAll:  dic_x.RemoveAll:   Set dic = Nothing: Set dic_x = Nothing
  65.     '设置大纲项目的汇总行在上方
  66.     With Outline
  67.         .AutomaticStyles = False
  68.         .SummaryRow = xlAbove
  69.         .SummaryColumn = xlRight
  70.     End With
  71.     Application.ScreenUpdating = True
  72. End Sub
  73. Sub DrawLevelBoxAndLine(iRow, iLevel, dic, dic_x, ssName)  '绘制树形框和连接线
  74.     Dim iCol&, nLeft!, nTop!, nWidth!, nHeight!, iParent&, aKeys, sName$, sParentName$
  75.     iCol = Columns(TR_COL_TREE_START).Column + (iLevel - 1) * 2    '计算绘图区起始列号
  76.     Columns(iCol - 1).ColumnWidth = TR_COL_LINE_WIDTH '设置连接线所在列列宽
  77.     Columns(iCol).ColumnWidth = Cells(1, TR_COL_NAME).ColumnWidth + TR_COL_LINE_WIDTH  '设置节点框所在列宽
  78.     With Cells(iRow, iCol)    '计算节点框位置和大小
  79.         nTop = .Top + TR_COL_BOX_MARGIN / 2
  80.         nLeft = .Left + TR_COL_BOX_MARGIN / 2
  81.         nWidth = .Width - TR_COL_BOX_MARGIN
  82.         nHeight = .Height - TR_COL_BOX_MARGIN
  83.     End With
  84.     sName = ssName    '获得节点框名称
  85.     With Shapes.AddShape(msoShapeRectangle, nLeft, nTop, nWidth, nHeight)    '绘制节点框
  86.         .TextFrame.Characters.Text = Cells(iRow, TR_COL_NAME).Text        '节点框内容为节点名称
  87.         .Name = sName        '设置节点框名为节点物料编码 (已处理有重复的情况)
  88.         .ShapeStyle = msoShapeStylePreset35
  89.     End With
  90.     If dic.Count = 0 Then Exit Sub    '如果堆栈内为空,则退出(不用画连接线)
  91.     aKeys = dic.keys  '获得堆栈内记录的行号赋值给数组
  92.     If iRow = aKeys(UBound(aKeys)) Then    '判断堆栈内最后一个节点与当前节点关系
  93.         If UBound(aKeys) = 0 Then Exit Sub '如果堆栈内最后节点同当前节点,且堆栈仅余一个节点,则退出(不用画连接线)
  94.         iParent = aKeys(UBound(aKeys) - 1)  '如果堆栈内最后节点同当前节点,则堆栈内倒数第二个节点为父节点
  95.     Else
  96.         iParent = aKeys(UBound(aKeys)) '如果堆栈内最后节点不同于当前节点,则堆栈内最后节点为父节点
  97.     End If
  98.     '获得父节点框名称
  99.     If dic_x(Cells(iParent, TR_COL_INDEX).Text) = 1 Then '当物料编码第一次出现时
  100.         sParentName = Cells(iParent, TR_COL_INDEX).Text '节点框名称==>物料编码
  101.     Else
  102.         sParentName = Cells(iParent, TR_COL_INDEX).Text & "_" & dic_x(Cells(iParent, TR_COL_INDEX).Text) '节点框名称+序号 '目的是为处理物料编码有重复的情况
  103.     End If
  104.    
  105.     With Shapes(sParentName) '计算连接线位置和大小
  106.         nLeft = .Left + .Width
  107.         nTop = .Top + .Height / 2
  108.         nWidth = nLeft - Shapes(sName).Left
  109.         nHeight = .Top - Shapes(sName).Top
  110.     End With
  111.     With Shapes.AddConnector(msoConnectorElbow, nLeft, nTop, nWidth, nHeight)    '绘制连接线
  112.         .Flip msoFlipHorizontal        '水平翻转
  113.         .Flip msoFlipVertical        '垂直翻转
  114.         .ConnectorFormat.BeginConnect Shapes(sParentName), 4        '起点为父节点框的第4个锚点
  115.         .ConnectorFormat.EndConnect Shapes(sName), 2        '终点为本节点框的第2个锚点
  116.         .Name = sParentName & "->" & sName        '设置连接线名称  父节点框->下级
  117.         .ShapeStyle = msoShapeStylePreset35
  118.     End With
  119. End Sub

  120. Sub Undo_All() '全部恢复
  121.     Dim i&, shp As Shape
  122.     Application.ScreenUpdating = False
  123.     With Cells
  124.         .EntireRow.AutoFit
  125.         .EntireColumn.ColumnWidth = TR_COL_LINE_WIDTH
  126.         .EntireColumn.AutoFit
  127.         .Interior.ColorIndex = xlNone
  128.         .Font.ColorIndex = 0
  129.         .ClearOutline  '清除所有分级
  130.     End With
  131.     Rows(1).RowHeight = TR_ROW_HEIGHT
  132.     For Each shp In Shapes
  133.         If shp.Type <> msoFormControl Then shp.Delete
  134.     Next
  135.     Application.ScreenUpdating = True
  136. End Sub
复制代码


分级.gif

按级别自动分组_新---.zip

30.53 KB, 下载次数: 161

TA的精华主题

TA的得分主题

发表于 2020-4-11 23:25 | 显示全部楼层
image.png
能否帮按照分类代码自动分组,分类代码的最底层8位数字

TA的精华主题

TA的得分主题

发表于 2020-4-12 17:11 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
在我看来,分组功能就是鸡肋,既丑陋又不实用!

也许以下这些方式能给予您启发:
链接: https://pan.baidu.com/s/1JZNfLp-0sj_wINA6bCdDaQ  提取码: fztk
链接: https://pan.baidu.com/s/1SLxDOkcLVr7oEpGrlGvCWg  提取码: enmc
链接: https://pan.baidu.com/s/10Vu9m02Egz8qpbd-Wmg9hg  提取码: ps7f

TA的精华主题

TA的得分主题

发表于 2020-11-18 09:29 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助

您好,我用您的附件下载后执行,但只是对前两行进行了分组,并没有像您展示的那样对所有数据进行分组,是怎么回事呢
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-14 15:12 , Processed in 0.052749 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表