字典在 VLisp 中的应用

来源:互联网 发布:信息软件 编辑:程序博客网 时间:2024/06/09 23:13

此处的 “字典”作为一种自动化的 ActiveX 对象,对应链接库文件为 scrrun.dll,在 Windows 系统内已默认注册,适用于 32/64 位系统。

字典对象是一种优化过的特殊数组,使用时不需声明固定长度,可自由增加数据。本文将字典对象引入 VLisp 语言,避开 Lisp 对超长表操作的效率低下问题。

以下代码在 64 位系统 Windows10 调试通过。

一、创建字典对象

(setq ob (vlax-create-object "Scripting.Dictionary"))

如果成功将返回一个 object 对象,下面将列出该对象的属性和方法

(vlax-dump-object ob t)

如果 ob 对象创建成功,则返回以下属性和方法:

;特性值:;   CompareMode = 0;   Count (RO) = 0;   Item = ...不显示带索引的内容...;   Item (RO) = ...不显示带索引的内容...;   Key (RO) = ...不显示带索引的内容...;支持的方法:;   Add (2);   Exists (1);   Items ();   Keys ();   Remove (1);   RemoveAll ()

VisualLisp 的对象操作函数和 AutoLisp 函数稍有区别,对属性或方法的操作,并不依赖返回值,操作成功时返回 nil.

二、字典对象的属性

字典的属性有 4 个:CompareMode 属性、Count 属性、Item 属性、Key 属性。相当于建立一个 (Key Item) 的二维数组,每个关键字对应一个 Item 属性,Item 属性很灵活,可以是数值或文本类型,也可以是数组或字典类型(嵌套字典)。此关键字在字典对象中唯一存在,类似 Lisp 表对结构,但 Lisp 表对 (a . b) 的第一项没有唯一性。

1. CompareMode 属性

设置字典对象中进行字符串关键字比较时所使用的模式,可以使用的值是 0 (二进制)、1 (文本), 2 (数据库)。默认为 0
在文本模式下,关键字的比较不分大小写,即 “AA” 和 “aa” 将被认为是同一个关键字。注意:如果试图改变一个已经包含有数据的 字典 对象的比较模式,那么将导致一个错误。

(vlax-get-property ob 'CompareMode)(vlax-put-property ob 'CompareMode 1)

2. Count 属性

获取字典内项目的个数,返回一个整数,如果字典为空,则返回 0,该属性为只读。

(vlax-get-property ob "count")

3. Item 属性

(1)获取指定关键字 “abc” 的项,如果关键字不存在,将返回一个未初始化的对象

(vlax-get-property ob 'Item "abc")

返回字典关键字对应项目为 Lisp 数据,可用自定义函数

(defun d_Item(d KEY)(vlax-variant-value (vlax-get-property d 'Item KEY)))

(2)给关键字 “abc” 指定一个项,如果关键字不存在,则创建;如果存在,则改写关键字的项,这个属性保证了关键字唯一性。

(vlax-put-property ob 'Item "abc" 66)

4. Key 属性

修改一个关键字的名称,如果旧关键字不存在,或者新关键字已经存在,都将返回一个错误。

(vlax-put-property ob 'key "abc" "ddd")

三、字典对象的方法

字典对象的方法有6个:Add 方法、Keys 方法、Items 方法、Exists 方法、Remove 方法、RemoveAll 方法。

1. Add 方法

给字典添加关键字 “abc” 值为 22,如果 “abc” 已存在,将返回一个错误。所以用 add 方法添加关键字前,需要先查找该关键字是否存在。用字典对象的 Item 属性来添加关键字时,不存在则添加,存在则改写。

(vlax-invoke-method ob "ADD" "abc" 22)

2. Keys 方法

返回字典关键字的一维对象数组,使用时需要先转为数组值,再转为 list 表

(vlax-invoke-method ob 'Keys)

3. Items 方法

返回字典项目的一维对象数组

(vlax-invoke-method ob 'Items)

将一维数组转为为 List 表可用以下自定义函数,调用:

(d_LKI d 'Keys)(d_LKI d 'Items)(defun d_LKI(d k)(mapcar 'vlax-variant-value (vlax-safearray->list     (vlax-variant-value (vlax-invoke-method d k)))))

4. Exists 方法

查询关键字 “abc” 是否存在,如果存在返回 :vlax-true,不存在则返回 :vlax-false

(vlax-invoke-method ob 'Exists "abc")

5. Remove 方法

从字典中清除一个关键字。如果 “abc” 不存在,将返回一个错误。

(vlax-invoke-method ob 'Remove "abc")

6. RemoveAll 方法

删除字典对象中所有关键字

(vlax-invoke-method ob 'RemoveAll)

四、 字典对象的应用

例1. 去掉重复值问题
由于字典中 key 值的唯一性,这个问题用字典解决非常合适。
加载通用子函数 d_Item、d_LtKI:

(defun d_Item(d k)(vlax-variant-value (vlax-get-property d 'Item k)))(defun d_LtKI(d k)(mapcar 'vlax-variant-value (vlax-safearray->list (vlax-variant-value (vlax-invoke-method d k)))))(setq L '("abc" "中国" "长城" "陕西" "中国" "北京" "abc" "a")) ;;准备数据

代码如下:

(defun d-DelSame(L / A L1)    (setq d (vlax-create-object "Scripting.Dictionary"))    (while (setq A (car L))        (vlax-put-property d 'Item A "")        (setq L (cdr L))    )    (setq L1 (d_LtKI d "Keys"))    (vlax-release-object d)L1)

去除重复元素一般用递归算法,但是对于超长表,可能会出现堆栈溢出错误。

(defun delsame (L)(if L (cons (car L)(delsame (vl-remove (car L) L)))))

两种方法效率测试如下,测试平台 AutoCAD 2012 x64、Inter core i7-6700
当表长度为 100 时, 字典耗时 0.004 秒, 递归耗时 0.001 秒
当表长度为 1000 时, 字典耗时 0.009 秒, 递归耗时 0.041 秒
当表长度为 5000 时, 字典耗时 0.054 秒, 递归耗时 2.016 秒
当表长度为 10000时, 字典耗时 0.106 秒, 递归函数已经溢出了,导致 CAD 崩溃。
结论:当表长度在100以下时,用递归方法效率很高;达到1000以上时不建议用递归;超过5000时,绝对不要用递归。

测试函数:

(defun test(n / AA)    (setq i 0 AA '())    (while (< i n) (setq AA (cons (setq i (1+ i)) AA)))    (setq time0 (getvar "date"))    (d-DelSame AA)    (setq time1 (getvar "date"))    (delsame AA)    (setq time2 (getvar "date"))    (princ (strcat "\n字典方法耗时: " (rtos (* 86400 (- time1 time0)) 2 4) " 秒"))    (princ (strcat "\n递归方法耗时: " (rtos (* 86400 (- time2 time1)) 2 4) " 秒"))(princ))

例2. 求重复值个数问题
以下代码返回统计重复元素后的二维表

(defun d-SameSum(L / A L1)    (setq d (vlax-create-object "Scripting.Dictionary"))    (while (setq A (car L))        (or (setq sum (d_Item d A)) (setq sum 0))        (vlax-put-property d 'Item A (1+ sum))        (setq L (cdr L))    )    (setq L1 (mapcar 'list (d_LtKI d "Keys")(d_LtKI d "Items")))    (vlax-release-object d)L1)
原创粉丝点击