马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
前几天大家讨论了求子表效率的问题,得到了结论,就是在循环里面获取连续的子表的时候尽量不要用nth函数,而是通过cdr和where结合取得各个位置的元素,这样效率最好,得到的结论好像是nth效率不高,
下面通过测试,来看看
下面函数是取得大表前n 项的子表
(l-where 3 '(1 2 3 4 5 6 7)) =>'(1 2 3)
 - ;;通过WHERE和CDR结合,通过取得表头元素获得当前位置的元素
- (defun l-where (n lst / a i v)
- (setq i 0)
- (while (and (< i n)
- (setq v (car lst))
- )
- (setq a (cons v a)
- lst (cdr lst)
- i (1+ i)
- )
- )
- a
- )
- ;;直接通过NTH得到具体位置的元素,构建连续的表
- (defun l-nth (n lst / a)
- (if (< n (length lst))
- (progn
- (setq i 0)
- (while (< i n)
- (setq a (cons (nth i lst) a)
- i (1+ i)
- )
- )
- )
- )
- a
- )
测试结果:
可以看出,用where实现的nth取得子表效率要高于用nth, 但是什么时候用nth都会慢吗?
下面通过用where,cdddr实现的nth和nth 就单个取一个元素来看看效率。
 - ;;标准nth
- (defun nth-nth(n lst)
- (nth n lst)
- )
- ;;where实现nth
- (defun nth-where (n lst)
- (setq i 0)
- (while (and (< i n)
- (setq v (car lst))
- )
- (setq i (1+ i)
- lst (cdr lst)
- )
- )
- v
- )
- ;;cdddr实现nth
- (defun nth-cdddr (n lst)
- (repeat (/ n 4)
- (setq lst (cddddr lst))
- )
- (repeat (rem n 4)
- (setq lst (cdr lst))
- )
- (car lst)
- )
上面测试表明,单独去一个具体位置的元素,nth 要 秒杀 用 cdddr,where实现的两个函数,差的数量级不是一点半点,表越长,取得的位置越靠后,nth 快的越多。
所以,nth不是什么时候都慢的,结论:
1、如果是只取得一个元素,标准的nth函数是最快的。
2、如果是在循环里面,要取得很多元素,这时候nth才慢于用cdr和where实现的,所以循环里面取得很多元素的时候,不建议用nth。
下面我们来单独测试下cdddr实现的nth 和 标准的 nth 自己和自己,取得不同位置元素的效率比较:
上面测试结果表明:
1、nth 函数在取得各个不同位置的元素,时间差别很小,所以ALISP的nth函数,绝不是顺序遍历内部表,一定是表在ALISP内部进行了特别的处理。绝不是从头遍历到指定位置。 90000的数据和1000的数据时间只是相差3秒多。
2、CDDDR和WHERE CDR实现的比较,都是从头往后面遍历顺序读取,因为CDDDR步幅是CDR的四倍,所以CDDDR要快了2倍多,但是90000和1000的时间差距是上百倍。
|