字典在 VLisp 中的应用

此处的 “字典”作为一种自动化的 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
)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yxp_xa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值