vectra 发表于 2015-12-2 20:52:16

打造随机访问的LISP可变长数组

本帖最后由 vectra 于 2015-12-2 20:58 编辑

LISP语言没有指针和引用,有时实在是不太方便,请看这个LISP可变长数组


;; 定义一个可以容纳len个数据的数组
(defun array-def (len uid / ar i)
(setq i 0)
(repeat len
    (setq ar (cons (read (strcat uid (itoa i))) ar)
          i(1+ i)
    )
)
(list uid (reverse ar))
)
;; 销毁数组对象并释放内存
(defun array-clear (ar /)
(foreach e (cadr ar)
    (set e nil)
)
)
;; 为数组指定索引位置赋值,成功返回值,失败返回nil
(defun array-set (ar i val / uid)
(setq uid (car ar))
(if (and (>= i 0) (< i (length (cadr ar))))
    (set (read (strcat uid (itoa i))) val)
)
)
;; 获取数组指定索引位置值
(defun array-get (ar i / uid)
(setq uid (car ar))
(if (and (>= i 0) (< i (length (cadr ar))))
    (vl-symbol-value (read (strcat uid (itoa i))))
)
)
;; 返回数组的容量
(defun array-length (ar /)
(length (cadr ar))
)
;; 重新设置数组的容量
(defun array-set-length      (ar len / count uid i tmp)
(setq      uid   (car ar)
      count (array-length ar)
)
(cond
    ((< len count)
   (setq ar (cadr ar))
   (repeat len
       (setq tmp (cons (car ar) tmp)
             ar         (cdr ar)
       )
   )
   (foreach e      ar
       (set e nil)
   )
   (list uid (reverse tmp))
    )

    ((> len count)
   (setq i 0)
   (repeat (- len count)
       (setq tmp (cons (read (strcat uid (itoa (+ count i)))) tmp)
             i         (1+ i)
       )
   )
   (list uid (append (cadr ar) (reverse tmp)))
    )
)
)
;; 返回数组的LISP格式数据
(defun array->list (ar /)
(mapcar 'vl-symbol-value (cadr ar))
)


演示:
_$(setq ar (array-def 3 "U"))
("U" (U0 U1 U2))
_$ (array-length ar)
3
_$ (array->list ar)
(nil nil nil)
_$(array-set ar 2 "222")
"222"
_$ (setq ar (array-set-length ar 10))
("U" (U0 U1 U2 U3 U4 U5 U6 U7 U8 U9))
_$ (array-length ar)
10
_$ (array->list ar)
(nil nil "222" nil nil nil nil nil nil nil)
_$(array-set ar 10 "222")          <- 下标是从0开始的,越界的下标造成赋值失败
nil
_$(array-set ar 9 "222")
"222"
_$(array-get ar 9)
"222"
_$ (array->list ar)
(nil nil "222" nil nil nil nil nil nil "222")
_1$ (array-clear ar)
nil
_1$ (array->list ar)
(nil nil nil nil nil nil nil nil nil nil)

看到length clear set get是不是找到点VB或者C的感觉来了呢。

大家也许都明白了,所谓的数组只不过是一组符号的管理器,符号是全局的,不要和已有的变量名称冲突呐。

当然,数组的访问实际上是直接对符号的访问,速度是相当快的,适合对性能有要求的随机访问,也没有了讨厌的subst cons操作了。



ivde 发表于 2015-12-2 23:45:51

lisp的优势是表,表本身就是可变的,变量放到 / 后面,函数运行结束,自动清除,(setq lst nil)就回收了,lisp虽然没有指针,但有自己特点,这样写反而失去表的灵活性了

vectra 发表于 2015-12-3 08:29:41

llsheng_73数据的修改确实比subst方便,但疑惑的是如果弄一个长度为10万的数组,需要10万个变量,会不会开销太大?

测试了一个一百万长度的表,生成表就花了一分钟,时间瓶颈在read函数上。后续读写非常快的。

内存方面没有明显感觉。

这只是提供了一个思路,解决一些特殊场景下的问题,并不是不分条件地使用。

ivde 发表于 2015-12-3 09:02:09

用alisper的理解就是构造 n 个全局变量,用一个表来收集符号型变量名以便清理,没必要套概念,lisp有高效简单方法

fl202 发表于 2015-12-3 09:15:16

一直没有明白:数组比表的优势在哪里?可否举例说明?谢谢!

或者说数组的作用?

ivde 发表于 2015-12-3 09:20:46

本帖最后由 ivde 于 2015-12-3 09:23 编辑

fl202 发表于 2015-12-3 09:15
一直没有明白:数组比表的优势在哪里?可否举例说明?谢谢!

或者说数组的作用?

数组直接开辟内存空间,用地址取值,但这不是lisp思想,用lisp就用lisp的思维方式

c++有数组,也有容器,我倒觉得vector更接近lisp思想

vectra 发表于 2015-12-3 09:31:17

本帖最后由 vectra 于 2015-12-3 09:33 编辑

fl202 发表于 2015-12-3 09:15 static/image/common/back.gif
一直没有明白:数组比表的优势在哪里?可否举例说明?谢谢!

或者说数组的作用?
当你需要频繁修改表里的数据时,数组的时间复杂度是1

lisp只有一种数据结构,就是链表,访问指定位置的时间复杂度是n

ivde 发表于 2015-12-3 09:40:04

vectra 发表于 2015-12-3 09:31
当你需要频繁修改表里的数据时,数组的时间复杂度是1

lisp只有一种数据结构,就是链表,访问指定位置的 ...

以你的需求为例,根据需求设置变量值(set (read (setq str(strcat "aaaa" (itoa n)))) var)
(setq $gllst (cons str $gllst))

取 n 的值只需要
(vl-symbol-value (strcat "aaaa" (itoa n))即可

fl202 发表于 2015-12-4 09:11:10

vectra 发表于 2015-12-3 09:31 static/image/common/back.gif
当你需要频繁修改表里的数据时,数组的时间复杂度是1

lisp只有一种数据结构,就是链表,访问指定位置的 ...

你说的时间复杂度是什么?
是指对表中的元素取值及赋值的速度吗?这个速度挺快的啊?
页: [1]
查看完整版本: 打造随机访问的LISP可变长数组