ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[求助] 不少版主看后都认为超难:全表代码寻优化提速,已写功能需求及原始数据清单

[复制链接]

TA的精华主题

TA的得分主题

发表于 2010-12-7 21:14 | 显示全部楼层
Option Explicit
Option Base 1    '所有数组都从1开始
Type final_list    '自定义数据结构,myname将存放每个人的名字,而mynumbers()数组将存放每个人的机号列表
    myname As String
    mynumbers() As Long
End Type
Sub 汇总机号()
    Dim name_dic, name_no_dic, name, name_no, name_machine() As final_list, machine_no
    Dim data_in, data_out, last_row, max_numbers As Long
    Dim i As Long, j As Long, new_record As Long, record_no As Long, arr_size As Long

    Set name_dic = CreateObject("Scripting.Dictionary")    '声明一个字典对象,用于快速查询人名
    Set name_no_dic = CreateObject("Scripting.Dictionary")    '声明一个字典对象,用于快速查询 "人名+机号"

    Workbooks("机号与型号.xls").Sheets("列出每人在本月所使用的机号").Select    '先清除旧的计算结果
    Range("A2:Z65535").Clear

    '读入所有的数据到VBA数组,这样所有计算都可以在VBA内部进行,不需要访问工作表,速度加快100倍以上
    Workbooks("机号与型号.xls").Sheets("人名-机数-齿数").Select
    last_row = [a65535].End(xlUp).Row
    data_in = Range("A2:P" & last_row).Value    '现在,data_in数组有 A2:P最后一行 的所有单元格数据

    '逐行处理这些数据
    new_record = 0                  '从0开始,准备汇总所有人的机号记录
    For i = LBound(data_in) To UBound(data_in)    '遍历data_in数组,也就等于遍历对应工作表的所有单元格数据
        name = data_in(i, 1)           '每行记录的第一列是人名
        machine_no = data_in(i, 2)    '第二列是机号
        name_no = name & "!" & machine_no    '重复的机号只记录一次,所以我们需要第二个字典,根据人名+机号去查询

        If Not name_dic.Exists(name) Then    '假如人名是新的
            new_record = new_record + 1    '那么记录累计+1
            name_dic.Add name, new_record    '把新的人名,以及对应的新的记录号写入字典。

            ReDim Preserve name_machine(1 To new_record)    '记录人名-机号汇总结果的数组, 其大小也增加1
            ReDim name_machine(new_record).mynumbers(1 To 1)    '把该数组元素(final_list自定义数据类型), 其存放机号列表的数组,大小设置为1
            name_machine(new_record).myname = name                 '该数组元素的人名,记录为当前行的人名
            name_machine(new_record).mynumbers(1) = machine_no    '此人的机号,记录为当前机号
            name_no_dic.Add name_no, new_record                                '同样地,把"人名+机号"也新增到 人名_机号字典。
        Else
            If Not name_no_dic.Exists(name_no) Then  '旧的人名肯定有机号记录,所以现在只需检查人名_机号字典,看看当前机号是否已经存在
                record_no = name_dic.Item(name)             '新的机号,则先找回此人名对应的final_list记录位置
                arr_size = UBound(name_machine(record_no).mynumbers)    '得到此记录的机号存放数组的大小
                ReDim Preserve name_machine(record_no).mynumbers(arr_size + 1)    '把记录机号的数组大小+1
                name_machine(record_no).mynumbers(arr_size + 1) = machine_no     '把新的机号存入数组末尾
                name_no_dic.Add name_no, new_record    '当然,字典也需要增加一项纪录,说明机号已经被保存
                If arr_size + 1 > max_numbers Then max_numbers = arr_size + 1    '这一句纯粹为了方便输出结果到工作表,有没有都可以
            End If
        End If
    Next i
    '到这里为止,我们已经把所有的人名-机号都存放在 name_machine数组
    '此数组每条记录都是 final_list 自定义类型,即一个人名,对应一串机号

    ReDim data_out(1 To UBound(name_machine), 1 To max_numbers + 1)    '现在,我们需要另一个数组,把汇总后的结果输出到指定位置
    For i = LBound(name_machine) To UBound(name_machine)       '把final_list的数据,逐一按格式复制到data_out数组
        For j = 1 To UBound(name_machine(i).mynumbers)
            data_out(i, 1) = name_machine(i).myname
            data_out(i, j + 1) = name_machine(i).mynumbers(j)
        Next j
    Next i
    '现在,我们把最终输出的数据,按格式放在了data_out数组,直接输出到工作表即可
    Workbooks("机号与型号.xls").Sheets("列出每人在本月所使用的机号").Select
    Range("A2").Resize(i - 1, max_numbers) = data_out
End Sub
'大功告成,我们在上面所有的代码,只读写工作表两次,第一次是读入所有数据,第二次是输出所有数据的汇总结果
'而且查询人名,机号是否属于新增记录,我们使用两个字典去查询,速度快如闪电。

TA的精华主题

TA的得分主题

发表于 2010-12-7 21:15 | 显示全部楼层
原帖由 secowu 于 2010-12-7 21:08 发表
1 绝对不在循环内部操作工作表,包括一切的cell,range函数,一切的.copy .paste .select,以及任何跟工作表有关的函数

这个不知道怎么处理

也不是绝对的,例如操作格式,就无法避免。
老师是说尽量用数组、字典,把数据读取到内存中,然后比较分析,再把结果、一次性写入工作表。【在内存中读取值和赋值的速度,远远快于工作表的读写】
COPY、PASTE,有别的方式替代。这样SELECT也少用了。

TA的精华主题

TA的得分主题

发表于 2010-12-7 21:35 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
呵呵,已经好长时间没有看到讨论如此热闹的帖子,而且还有这么多高手献艺,只是楼主的标题是不是应该换一换呢

TA的精华主题

TA的得分主题

发表于 2010-12-7 21:51 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
原帖由 camle 于 2010-12-7 20:40 发表

原来写的啥?来晚了,跪求真相!


一直有个疑问, camle兄的名字是不是camle啊?

camle这个词 好像英语里面是没有的哇。

至于真相嘛,, camle可以call花MM问问。哈哈

TA的精华主题

TA的得分主题

发表于 2010-12-7 21:57 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
真是强悍的贴子,聚集了这么多高人,叩拜各位高人,我是你们的粉丝

TA的精华主题

TA的得分主题

发表于 2010-12-7 22:01 | 显示全部楼层
原帖由 AVEL 于 2010-12-7 21:51 发表


一直有个疑问, camle兄的名字是不是camle啊?

camle这个词 好像英语里面是没有的哇。

至于真相嘛,, camle可以call花MM问问。哈哈

老兄不抽烟的吧,烟鬼估计没几个不知道这个牌子的...
那个真相么,花花早就坦白交代了...今天真是够欢乐的.

TA的精华主题

TA的得分主题

发表于 2010-12-7 22:12 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
原帖由 camle 于 2010-12-7 22:01 发表

老兄不抽烟的吧,烟鬼估计没几个不知道这个牌子的...
那个真相么,花花早就坦白交代了...今天真是够欢乐的.

被你点穿了,我的确不抽烟的。
呵呵。 出糗了。

TA的精华主题

TA的得分主题

发表于 2010-12-7 22:14 | 显示全部楼层
原帖由 secowu 于 2010-12-7 21:08 发表
1 绝对不在循环内部操作工作表,包括一切的cell,range函数,一切的.copy .paste .select,以及任何跟工作表有关的函数

这个不知道怎么处理

老师忽悠人 不带这样的
43楼的代码,附上附件呗,很多人想学的。
头像被屏蔽

TA的精华主题

TA的得分主题

发表于 2010-12-7 22:19 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

TA的精华主题

TA的得分主题

发表于 2010-12-7 22:21 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
原帖由 excelflower 于 2010-12-7 22:14 发表

老师忽悠人 不带这样的
43楼的代码,附上附件呗,很多人想学的。

不用附.灰袍大大的附件里就有....
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-22 04:12 , Processed in 0.037200 second(s), 5 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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