用词典查找代替VLOOKUP

从上一篇《PYTHON操作EXCEL》可以看到,Python 操作 Excel 已非常自如方便。但是 Python 和相关库毕竟是一个额外的依赖,若能从 Excel 自身解决此类问题,自然是更为易用。

1. VBA 中的哈希表

用 Python 的着眼点主要是 VLOOKUP 公式太慢了,所以关键是要找到一种更高效的算法或数据结构定位数据。VLOOKUP 要求对列进行排序,内部应该是对列内数据进行二分查找,算法上不好再优化了,那就只好更换一种数据结构。搜索了一下,VBA 提供了 Scripting.Dictionary 这一词典结构,而且有文章说内部是哈希表实现,那就正是我要的东西了。

这样,VLOOKUP(lookup_value,table_array,col_index_num,range_lookup) 这一公式就转为下面的词典查找方式来实现:

  • 使用要从中进行查找的 table_array 内容构建词典。用 table_array 第一列作为 key,table_array 第 col_index_num 列作为 value,插入 Dictionary 中:Dictionary.Add key, value;
  • 查找时只需直接取 Dictionary 内的值 Dictionary.Item(lookup_value),即可完成查找;

若是仅仅 VLOOKUP 一次,倒也不必费劲先建立起一个词典。但当使用同样 VLOOKUP 公式的单元格很多时(比如几万个),就显得其必要了。因为 Dictionary 只需要建立一次,就可以用 O(1) 的复杂度进行多次查找了。

2. VLOOKUP 慢,主要问题不在算法上

从算法角度,词典查找的确快于二分查找,但优势并不是那么明显。所以在具体执行时,我发现使用词典查找的 VBA 宏运行速度并不比 VLOOKUP 快多少,运行时 Excel 仍然会导致系统假死几个小时。按说如此简单的程序不应该那么慢,问题究竟在哪里呢?

经过一段摸索,我才发现问题的根源所在:

  • VBA 往 Excel 表格中填内容时,会引发表格中已有公式的自动计算,非常耗时;
  • Excel 表格内容更新时,会触发屏幕显示内容的自动刷新,代价也很高;

所以提高 VBA 脚本执行性能的关键点,在于计算时关掉公式自动计算和屏幕刷新,这也是我始料未及的。在 VBA 中实现这两点很容易,但由于 VLOOKUP 本身即是公式,我没能想通直接调用 VLOOKUP 时如何避免这两点带来的性能损失。

3. 示例 VBA 代码

在做了上面提到的两次优化之后,原来 VLOOKUP N 个小时才能完成的任务,只用了 7 秒钟就执行结束了。

下面是我写的一段示例代码。我不熟悉 VBA 语言,只是照葫芦画瓢。代码规范程度相差甚远,但题意应是体现其中了。有心的朋友可以用作参考。

Sub 在机器表上生成一级分中心()
'
' 在机器表上生成一级分中心 Macro
'
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False

t0 = Timer
' 词典
Set map_dict = CreateObject("Scripting.Dictionary")

' 打开分中心映射表
Set map_sheet = Worksheets("分中心映射表")
map_nrows = map_sheet.Range("A300").End(xlUp).Row
Set my_rows = map_sheet.Range("A2:B" & map_nrows).Rows

' 遍历分中心映射表,获得 分中心 对应的一级分中心,插入词典
For Each my_row In my_rows
   center = my_row.Cells(1, 1).Value
   city = my_row.Cells(1, 2).Value
   If Not map_dict.Exists(center) Then
       map_dict.Add center, city
   End If
Next my_row

' 打开机器表
Set dispatch_sheet = Worksheets("机器表")
dispatch_nrows = dispatch_sheet.Range("G99999").End(xlUp).Row
Set my_rows = dispatch_sheet.Range("K2:L" & dispatch_nrows).Rows

' 遍历开通表,通过词典获得 machine_id 对应的一级分中心,插入开通表
For Each o_row In my_rows
   center = o_row.Cells(1, 1).Value
   o_row.Cells(1, 2).Value = map_dict.Item(center)
Next o_row

MsgBox "在机器表上生成一级分中心。共处理 " & dispatch_nrows & " 条记录,总耗时" & Timer - t0 & "秒。"

' 销毁建立的词典
Set map_dict = Nothing

' 打开自动计算和屏幕刷新
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
'
End Sub

最后补充一点:我先实现的词典查找,后发现性能问题根源,所以未能去比较 VLOOKUP 与词典查找两种方式的具体性能差异。我想如果差异可以忍受,那么直接在 VBA 中调用 VLOOKUP 公式或许是一种更为简单的实现。

A Chance For Linux and Freeware

连着忙了几天,今天闲话几句。

关于微软正版验证

我家希希说:“我要被黑屏了,怎么办呀?我要学 Linux!”

我说:“没关系,你把自动更新服务关掉就行了。”

我家希希说:“我还是想学 Linux!”

微软准备在 2008 年 10 月 20 日对中国用户启动的 WGA 计划这几天被吵得沸沸扬扬,搞得几乎人人自危,生怕被黑屏了。本人的评论如下:

  • 对此措施,我持欢迎态度。这件事起码给中国的盗版用户提了个醒:软件是有知识产权的!用盗版的操作系统很开心,用盗版的应用软件也很开心,到最后是中国整个落后的软件产业不开心,软件民工们也不开心。

  • 对于效果,我持保留态度。我相信中国盗版产业中广大劳动人民的智慧!

  • 对于影响,我持乐观态度。这是一个 Linux 和免费软件的机遇。此次 WGA 计划一出,势必会督促那些已经有学习其它操作系统愿望的用户真正动起手来,也会使那些使惯了盗版 Office 的人考虑一下免费的优秀国产软件 WPS Office,进而认识到许多优秀的免费软件并不比收费软件差

最后友情提醒一下,WPS Office 2007 目前已更新到支持 M$ Office 2007 文件格式( .docx, .xlsx, .pptx ),永中也于本月 13 号推出了免费的永中 Office 2009 个人版,支持 Windows 和 Linux 平台;免费的国产软件 Foxmail 和"进口软件" Thunderbird 都可以替代 Outlook ; Ubuntu 8.10 Linux 操作系统还有 14 天就发布了。

关于看论文

最近被老师逼着快速浏览了大量论文,发现自己以前看论文的效率还是太低。眼高手低的毛病总是改不了,做研究还是要潜心进去。

关于看书

每天睡前逼着自己看一会儿书效率挺高的。豆瓣上我在读的书已经超过二十本了,平日很难分出大块时间看,目前已经利用睡前十分钟解决了两本。躺床上用台灯看书的感觉蛮惬意的,置身于黑暗中的一小片光明,仿佛又回到了中学时代。当然这也得益于现在宿舍的环境布置,床头就是写字桌,要是像以前在中关村时住上铺的话,势必就会影响室友的睡眠了。

关于 writeos

九月份更新了两次,十一假期无暇写字,第三章到现在还没写完,我希望十月底能完成发布第二个版本。上个星期一个墨西哥的小伙子加我 Gtalk,问这本书的问题,开始我还以为是华裔,后来知道人家根本不懂中文,没办法只好推荐他去看代码注释。也许等我再完成两章之后,会和某些朋友合作开始将它翻译成英文。

金山公司花巨资为 WPS Office 从 Design Science 引进了公式编辑器

提起 Design Science 公司大家可能并不熟悉,但是说到 M$ Office 里的公式编辑器和 MathType,大概大家就不会觉得陌生了。对,公式编辑器和 MathType 都是 Design Science 公司的产品。

这不是一则新闻,不过也不旧,这件事发生在 2008 年 5 月 8 日,金山公司对外宣布金山公司巨资购买公式编辑器 回馈WPS 用户。Design Science 也在网页上显著位置(高于微软)将金山公司列为战略合作伙伴

自从半年前放弃盗版的 M$ Office 投入到 WPS Office 永久免费的个人版阵营之后,我不断地发现 WPS Office 的优点(当然了,其最大的优点是免费)。WPS Office 能对 Office 文档格式(.doc, .ppt, .xsl)相当完美的兼容,与 OpenOffice 那种兼容不是一个数量级的。我最喜欢的还有一个功能:直接导出 pdf 格式文档。但是其缺乏公式编辑器也让我很苦恼,就在前几天,在完成一门课程作业时(中国的老师怎么那么喜欢用 Word 文档留作业且作为提交格式啊?),我不得不到一个在线的 TeX 网站去生成要用到的公式图片,再下载了插入到 WPS 文档中。

今天我到金山的网站去下载更新的 WPS 的时候(我讨厌自动更新),忽然在一个角落里发现了 WPS 添加公式编辑器的新闻,这个消息让我很振奋。这个功能将大大地提高 WPS Office 的易用性,而且可以促使更多人有理由放弃盗版的 M$ Office。我将其记录在我的博客里,也希望看到的人能够(至少尝试一下)迁移到 WPS Office 平台上工作,为减少中国被国外诟病的软件侵权行为出一分力。(我女朋友现在就一直使用 WPS,因为当初我骗她说这是精简版的 Office ^_^,我室友也在我的强烈呼吁下部分转移到了 WPS Office 平台。)

其实我应该算是 WPS 的老用户了,在 1998 年,我刚开始接触电脑的时候,学会用电脑打字使用的就是 WPS,当时记忆深刻的就是它的崩溃频率,基本上一上午至少要崩溃两次,辛辛苦苦打的东西唰就全变成乱码了。不过 WPS 也在发展,它曾两度(2001年和2007年)荣获国家科技进步二等奖,大概是国产软件获得的国家级最高奖项了吧。金山公司2007年8月份做出了将个人版免费发布的决定,我认为这个决定将为中国办公软件的正版化做出不可磨灭的贡献。