Excel精英培训网

 找回密码
 注册
数据透视表40+个常用小技巧,让你一次学会!
查看: 3086|回复: 6

[分享] Excel VBA 字典对象详解 by Air China Michen

[复制链接]
发表于 2013-11-15 12:03 | 显示全部楼层 |阅读模式
我花了6个小时读懂了大师的代码, 为了避免健忘我这里做个详细的叙述,注意教课书是不会说的这么细的.

Sub dit3()

    Application.Volatile            定义函数为易失, 已使 其在单元格改变时,自动更新数据.
    On Error Resume Next    如果出现错误则继续,因为字典避免重复,重复就装不进去,所以必须让程序出了错误continue到
                                           下一次循环。
    Dim answer As String       定义字符串变量。
    Dim a As String
    Dim Arr11, LastRow, LastRow2, Arr, Arr1  定义整形变量。
    Dim Arr21(), Arr22()         定义2个数组。

    Set D = CreateObject("scripting.dictionary")   定义2个字典对象,这个字典和现实中的字典几乎一样,健无重复。
    Set d1 = CreateObject("scripting.dictionary")


    With Sheet2      注意,sheet2这个表示为了装入字典而写好的2维表(航班号 承运人)key/value pair。

        LastRow = .Range("A65536").End(xlUp).Row     找到这个作为字典源的最后以行数据。
        Rem lastrow 的值为 2001 sheet2     因为有2000行数据,所以加上标题 输出值为 2001。
              
        注意以下不好理解了:   
        Arr11 = .Range("A2:B" & LastRow)     把2列2000行的字典用根数据作为 2维数组装入 2维数组 Arr11。
              Rem MsgBox UBound(Arr11) 2000 下届为1   :这里debug.print 输出了数组的上,下届以方便理解。
                                    
            End With

既然数据已经装入了数组,则现在开始完数组,以在内存中完成任务。

    For i = 1 To UBound(Arr11)  注意Arr11 的内容 实际为 sheet2!A2:B2000 (只是作为基准的输入字典用的根key/value数据表)注意实际 For i = 1 to 2000

        If Not D.Exists(Arr11(i, 1)) Then   这是为了防止根数据存在相同的航班号而做的去除重复处理。
            n = n + 1    如果能装入字典的话 则 计数器就 +1 。
            D(Arr11(i, 1)) = n     左边是不重复的航班号,右边是自然数。
            ReDim Preserve Arr21(1 To 2, 1 To n) 定义新的可变数组,并保留原值。定义了一个 1-2 行,1 到 n 列的 2维数组。
            Arr21(1, n) = Arr11(i, 1)  数组之间的负值开始了, 右边的其实是原表格中第一列的不重复的航班号,
                                                   在向左边的负值中,其实反转了数据 (行列互换了) 注意现在数组第一行为不重复的航班号了。
            Arr21(2, n) = Arr11(i, 2)   注意右边的其实是原表格的写好的某个航班号的实际承运人列表。
                                                    行列互换后向左边负值。注意这个 i 不是自然数,因为前面有过字典判断所以 如果
                                                     有重复的话 i 会自动跳过重复航班号的行数。
        End If
    Next
Rem n的值为2000 是字典对的 个数。sheet2

  Rem 以上产生了一个不重复的数组 Ar21 上面是航班号,下面是承运人,不重复数组已经搞定。
  
  Rem Arr21 留着以后用 是一个第一行是航班号,第二行是承运人的两行表。且删除了重复。
这里已经大功告成了一半。  
   

简单的说数据源曾是通过2层循环执行判断的,第一层循环,在每个单元格内,第二层循环在 所有那一例里循环。
看过 盗梦空间a吗? 就是 tiered dream in a dream
   
Rem 下面到了数据源层面
    With Sheet1
        LastRow2 = .Range("A65536").End(xlUp).Row   找到数据源层的最后一行。
       Rem MsgBox LastRow2 求值为1001 sheet
               
        
        Arr = .Range([A2], "A" & LastRow2)      把需要判断的那个列整个装入 1维数组。
      Rem  MsgBox LBound(Arr)
      
        
        Rem Ubound(Arr) 一维 数组上届为 1000 下届 为1
        
    End With
   
    ReDim Arr22(1 To UBound(Arr), 1 To 1)   注意Arr22 是第一次出现,他的目的是,为了装入 以上Arr载入的一纬数据源。
    Rem 把已经定义好的字典定义成与数据源相同的高度且保留值        ,是多行1列的数组。
   

    Rem Arr 为实际数据源的1维数组
   
    For i = 1 To UBound(Arr)
    Rem 遍历数据源 1 to 1000 数据源重要
   
   
        Arr1 = Split(Arr(i, 1), "-")
        Rem 将数据源每行分割后给数组 Arr1   ,将每个单元格的数据 用 - 拆分后放入数组Arr1。
        
               
        
               
        For j = 0 To UBound(Arr1)
            cy = Arr21(2, D(Arr1(j)))      注意Arr21 的第2行是实际承运人, 注意这个D()字典的值是自然数。
            所以根据2维数组的 行 列 号 即可以返回实际的值,也就是 承运人是谁?
            Rem 由于字典的值是列数所以根据航班号可以返回字典的值也就是列数 所以cy已经返回承运人了
            
            If Not d1.Exists(cy) Then   注意字典d1 是第一次出现,注意那个 not 也就是说只有字典的 值不存在实才往下执行
否则跳过。
                answer = answer + Arr21(2, D(Arr1(j))) & " "   把答案 Arr21 的第2行 第 n 列 恰好是实际承运人(答案)负值给anser.
               n1 = n1 + 1  负值成功一次 自然数+1 。
               d1(cy) = n1    注意字典的值是自然数。       让字典d1 的值为自然数n1。
              
               
               
              
               
            End If
        Next j
        
      
        Rem n1 为被分割的航班号在能在字典中能查到的不重复的个数。
        Rem 如果n1 即航班号出现过那么 字典肯定就不能在输入键了
        Rem 这样巧妙的删除了重复
        
        
        
               
        
      
        Arr22(i, 1) = answer  Arr22 的行数与sheet 1数据源相同,1为第一列。 注意 i  是跳跃的自然数(行数)
                            结果是对符合条件的行进行 判断结果注释。
        
        answer = ""  释放变量
      
              
        n1 = 0   释放变量

        d1.RemoveAll   释放变量

    Next i            选换下一行。
   
   
   
    Sheet1.[b2].Resize(UBound(Arr22), 1) = Arr22    将数组Arr22 一次写入数据源sheet1 判断列单元格。
End Sub



  

评分

参与人数 1 +3 收起 理由
yyyydddd8888 + 3 赞一个!

查看全部评分

excel精英培训的微信平台,每天都会发送excel学习教程和资料。扫一扫明天就可以收到新教程
发表于 2013-11-15 12:05 | 显示全部楼层
回复

使用道具 举报

发表于 2013-11-15 12:55 | 显示全部楼层
写注释是非常好的习惯,继续加油。
回复

使用道具 举报

发表于 2013-11-15 13:01 | 显示全部楼层
谢谢分享!
回复

使用道具 举报

发表于 2013-11-20 15:37 | 显示全部楼层
错别字比较多,On Error Resume Next 最好不用,作为初学者(如果是的话)很不错了,表扬!
回复

使用道具 举报

发表于 2013-11-20 16:24 | 显示全部楼层
就是,On Error Resume Next 不可滥用,要不然,啷个死的都不晓得
一般都是要利用错误陷阱时才用
另:如果作为代码收集,最好收集经典的,简明、清晰的

评分

参与人数 1 +1 收起 理由
大灰狼1976 + 1 :handshake

查看全部评分

回复

使用道具 举报

 楼主| 发表于 2013-11-22 12:20 | 显示全部楼层
好的
,求 上官大人 给改成 不用 on error resume next.
回复

使用道具 举报

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

本版积分规则

小黑屋|手机版|Archiver|Excel精英培训 ( 豫ICP备11015029号 )

GMT+8, 2024-4-29 18:57 , Processed in 0.300644 second(s), 14 queries , Gzip On, Yac On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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