ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

请教用字典嵌套,提取BOM不同层级数据

[复制链接]

TA的精华主题

TA的得分主题

发表于 2024-7-15 16:59 | 显示全部楼层 |阅读模式
BOM层级仅2级

第一级为楼栋
第二级为对应专业

提取数据 源数据表中 C列中
第一级提取至  目标表中 A列,第一级字典
第二级提取至  目标表中 C列,字典嵌套,对应数据为建筑面积,工程造价,建筑指标
(详见目标表格式)

已写代码
  1. Sub ExtractDataUsingDictionary()
  2.     Dim srcSheet As Worksheet
  3.     Dim tgtSheet As Worksheet
  4.     Dim srcRange As Range
  5.     Dim lastRowSrc As Long
  6.     Dim dict As Object
  7.     Dim subDict As Object

  8.     '设置源数据工作表和目标表工作表
  9.     Set srcSheet = ThisWorkbook.Sheets("源数据")
  10.     Set tgtSheet = ThisWorkbook.Sheets("目标表")

  11.     '获取源数据工作表的最后一行
  12.     lastRowSrc = srcSheet.Cells(srcSheet.Rows.Count, "C").End(xlUp).Row

  13.     '创建字典
  14.     Set dict = CreateObject("Scripting.Dictionary")

  15.     '提取数据到字典
  16.     For i = 2 To lastRowSrc
  17.         If InStr(srcSheet.Cells(i, "C"), "栋") > 0 Then
  18.             '创建新的子字典
  19.             Set subDict = CreateObject("Scripting.Dictionary")
  20.             If Not dict.Exists(srcSheet.Cells(i, "C")) Then '检查键是否已存在
  21.                 dict(srcSheet.Cells(i, "C")) = subDict
  22.             Else
  23.                 MsgBox "重复的楼栋键: " & srcSheet.Cells(i, "C")
  24.                 Exit Sub
  25.             End If
  26.         End If
  27.         If dict.Exists(srcSheet.Cells(i, "C")) Then
  28.             On Error Resume Next '添加错误处理
  29.             subDict(srcSheet.Cells(i, "C")) = Array(srcSheet.Cells(i, "L"), srcSheet.Cells(i, "C").Offset(0, 1), srcSheet.Cells(i, "D"), srcSheet.Cells(i, "M"))
  30.             If Err.Number <> 0 Then '检查是否发生错误
  31.                 MsgBox "在处理数据时发生错误: " & Err.Description
  32.                 Err.Clear '清除错误
  33.             End If
  34.             On Error GoTo 0 '恢复默认的错误处理
  35.         End If
  36.     Next i

  37.     '将字典数据写入目标表
  38.     i = 2
  39.     For Each Key In dict.Keys
  40.         tgtSheet.Cells(i, 1) = Key
  41.         For Each subKey In dict(Key).Keys
  42.             tgtSheet.Cells(i, 2) = dict(Key)(subKey)(0)
  43.             tgtSheet.Cells(i, 3) = dict(Key)(subKey)(1)
  44.             tgtSheet.Cells(i, 4) = dict(Key)(subKey)(2)
  45.             tgtSheet.Cells(i, 5) = dict(Key)(subKey)(3)
  46.             i = i + 1
  47.         Next subKey
  48.     Next Key
  49. End Sub
复制代码
字典嵌套提取.rar (23.92 KB, 下载次数: 3)
目前存在问题,请各位老师帮帮忙修改下代码,谢谢

TA的精华主题

TA的得分主题

发表于 2024-7-16 00:07 | 显示全部楼层
字典嵌套提取123.rar (25.63 KB, 下载次数: 7)

TA的精华主题

TA的得分主题

发表于 2024-7-16 09:49 | 显示全部楼层
其实不需要用字典的
Sub 拆分abc()
Dim arr, brr(1 To 10000, 1 To 5)
Application.DisplayAlerts = False
Application.ScreenUpdating = False
With Worksheets("源数据")
  r = .[c65536].End(xlUp).Row
  arr = .Range("a1:m" & r)
  Rng = Array("楼栋号", "建筑面积", "专业名称", "工程造价(元)", "建筑指标(元/㎡)")
  For i = 3 To UBound(arr)
    If InStr(arr(i, 3), "栋") <> 0 Then
      mx = arr(i, 3)
    Else
      n = n + 1
      brr(n, 1) = mx
      brr(n, 2) = arr(i, 12)
      brr(n, 3) = arr(i, 3)
      brr(n, 4) = arr(i, 4)
      brr(n, 5) = arr(i, 13)
    End If
  Next
End With
With Worksheets("目标表")
  .Range("a1").Resize(1, 5) = Rng
  .Range("a2").Resize(UBound(brr), UBound(brr, 2)) = brr
End With
Application.DisplayAlerts = True
Application.ScreenUpdating = True
MsgBox "ok!", 64
End Sub

评分

1

查看全部评分

TA的精华主题

TA的得分主题

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

感谢,完美解决,附上中文解释
  1. Sub 拆分abc123释义()
  2.     '定义数组arr和brr
  3.     Dim arr, brr
  4.     '创建一个Scripting.Dictionary对象
  5.     Set d = CreateObject("scripting.dictionary")
  6.     '关闭显示警告和屏幕更新
  7.     Application.DisplayAlerts = False
  8.     Application.ScreenUpdating = False
  9.     '在"源数据"工作表中进行操作
  10.     With Worksheets("源数据")
  11.         '获取C列最后一个有数据的行号
  12.         r = .[c65536].End(xlUp).Row
  13.         '将A1:M列的数据赋值给数组arr
  14.         arr = .Range("a1:m" & r)
  15.         '定义一个包含特定表头名称的数组
  16.         Rng = Array("楼栋号", "建筑面积", "专业名称", "工程造价(元)", "建筑指标(元/㎡)")
  17.         '从第3行开始循环到数组arr的上界
  18.         For i = 3 To UBound(arr)
  19.           If arr(i, 2) <> "" Then
  20.             '如果第3列的单元格值包含"栋"字
  21.             If InStr(arr(i, 2), ".") = 0 Then
  22.                 '将当前单元格值赋值给变量mx
  23.                 mx = arr(i, 3)
  24.             Else
  25.                 '如果字典d中不存在mx这个键,新建字典,key为mx
  26.                 If Not d.exists(mx) Then
  27.                     '初始化计数器m为1,当key为新key时,并重新定义brr数组
  28.                     m = 1
  29.                     ReDim brr(1 To 5, 1 To m)
  30.                 Else
  31.                     '获取字典中mx对应的值(即brr数组)
  32.                     brr = d(mx)
  33.                     '更新计数器m
  34.                     m = UBound(brr, 2) + 1
  35.                     '重新调整brr数组大小
  36.                     ReDim Preserve brr(1 To 5, 1 To m)
  37.                 End If
  38.                 '为brr数组赋值
  39.                 brr(1, m) = mx
  40.                 brr(2, m) = arr(i, 12)
  41.                 brr(3, m) = arr(i, 3)
  42.                 brr(4, m) = arr(i, 4)
  43.                 brr(5, m) = arr(i, 13)
  44.                 '将brr数组存入字典d,键为mx
  45.                 d(mx) = brr
  46.             End If
  47.           End If
  48.         Next
  49.     End With
  50.     '定义新的数组zrr
  51.     Dim zrr(1 To 10000, 1 To 5)
  52.     '遍历字典d的键
  53.     For Each aa In d.keys
  54.         '获取字典中对应键的值(即数组arr)
  55.         arr = d(aa)
  56.         '循环处理数组arr
  57.         For j = 1 To UBound(arr, 2)
  58.             '计数器n递增
  59.             n = n + 1
  60.             '将arr的值复制到zrr中,转置
  61.             For i = 1 To UBound(arr)
  62.                 zrr(n, i) = arr(i, j)
  63.             Next
  64.         Next
  65.     Next
  66.     '在"目标表"工作表中进行操作
  67.     With Worksheets("目标表")
  68.         '在A1单元格写入表头
  69.       .Range("a1").Resize(1, 5) = Rng
  70.         '将zrr数组的值写入到指定区域
  71.       .Range("a2").Resize(UBound(zrr), UBound(zrr, 2)) = zrr
  72.     End With
  73.     '恢复显示警告和屏幕更新
  74.     Application.DisplayAlerts = True
  75.     Application.ScreenUpdating = True
  76.     '弹出消息框显示"ok!"
  77.     MsgBox "ok!", 64
  78. End Sub
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-7-16 10:29 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
abc123281 发表于 2024-7-16 09:49
其实不需要用字典的
Sub 拆分abc()
Dim arr, brr(1 To 10000, 1 To 5)

代码更简单了,厉害
可能被标题误导了

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-7-16 10:37 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 lele400024 于 2024-7-16 10:39 编辑
abc123281 发表于 2024-7-16 09:49
其实不需要用字典的
Sub 拆分abc()
Dim arr, brr(1 To 10000, 1 To 5)

想到了一个有意思的,如果有三级呢,这个只有两级,如果有三级分级,怎么提取呢,是不是就要字典了

TA的精华主题

TA的得分主题

发表于 2024-7-16 13:36 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
lele400024 发表于 2024-7-16 10:37
想到了一个有意思的,如果有三级呢,这个只有两级,如果有三级分级,怎么提取呢,是不是就要字典了

1 注释写得正确,理解到位。
2 如果有三级,那要看数据表是什么样子的,针对性的来使用字典,有时也不一定需要使用字典。



您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-10-18 12:51 , Processed in 0.044694 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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