明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1455|回复: 20

[讨论] 关于如何代替nth问题?

[复制链接]
发表于 2021-8-16 21:58 | 显示全部楼层 |阅读模式
nth  函数比较慢,为了解决这个问题  
car cadr caddr cadddr   可以解决4个,那么多的表格,还是需要它。

这几天再考虑,是不是可以弄个函数出来,把多的表格也一并处理了。。。。。


"觉得好,就打赏"
还没有人打赏,支持一下
发表于 2021-8-17 21:56 | 显示全部楼层
本帖最后由 tryhi 于 2021-8-17 22:08 编辑
不死猫 发表于 2021-8-17 16:43
不用测了,组合car cdr比nth快的多

不对吧,我觉得无法写出一个能替代nth的函数,只有在某些特定情况的算法可以用car cdr来代替nth,但是想要在一个100万个元素的表里面取出其第50万个元素的值,我觉得nth没有可替代性

;;测试用cdr取第50万个时间(repeat版)  结果79毫秒
(defun c:t1 (/ i lstx)
        (setq lstx nil i 0)
        (repeat 1000000 (setq i(1+ i) lstx(cons i lstx)));;生成100万个元素的表
        (try-time-be);计时开始
        (repeat 500000
                (setq lstx(cdr lstx))
        )
        (setq r(car lstx));第50万个的值
        (try-time-end nil t);计时结束
)

;;测试用cdr取第50万个时间(while版)  结果83毫秒
(defun c:t2 (/ j i lstx)
        (setq lstx nil i 0 j 0)
        (repeat 1000000 (setq i(1+ i) lstx(cons i lstx)));;生成100万个元素的表
        (try-time-be);计时开始
        (while (< j 500000)
                (setq lstx(cdr lstx)
                        j(1+ j)
                )
        )
        (setq r(car lstx));第50万个的值
        (try-time-end nil t);计时结束
)

;;测试用nth的时间  结果2毫秒
(defun c:t3 (/ i lstx)
        (setq lstx nil i 0)
        (repeat 1000000 (setq i(1+ i) lstx(cons i lstx)));;生成100万个元素的表
        (try-time-be);计时开始
        (setq r(nth 500000 lstx));第50万个的值
        (try-time-end nil t);计时结束
)
结果是nth完胜,顺带回答题主的问题,nth具有不可替代性,任何可以通过不使用nth来优化的算法,都具有一定特殊性或局限性


回复 支持 2 反对 0

使用道具 举报

发表于 2021-8-17 06:45 | 显示全部楼层
本帖最后由 baitang36 于 2021-8-17 06:59 编辑

lisp的表在内存中的数据结构是cons,也就是一个链表。每个节点包含下一节点的地址和本节点的内容。表的每个元素在内存中都是不连续的。链表只能从从头开始查询,遍历起来速度慢。
字符串在内存中是连续存放的,你可以试试改成字符串,然后用substr来处理,速度应该能快。
你的测试有问题,(princ (nth 4 lst))这句中的princ速度很慢,你测的是它的速度,不是nth的速度。
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2021-8-17 00:10 | 显示全部楼层
本帖最后由 尘缘一生 于 2021-8-17 01:36 编辑

弄了个,似乎可以,然而。。。。。。???

    • ;;nth替代函数--------(一级)----------
    • (defun nnth (i lst / k)
    •   (setq loop t k 0)
    •   (while loop
    •     (setq numlis (car lst))
    •     (if (/= k i)
    •       (setq lst (cdr lst) k (1+ k))
    •       (setq loop nil)
    •     )
    •   )
    •   numlis
    • )
    • ;测试-------13秒
    • (defun c:tt1 ()
    •   (setq t0 (getvar "TDUSRTIMER"))
    •   (setq lst (list "1" "2" "3" "4" "5") i 1)
    •   (while (< i 90000)
    •     (princ (nnth 4 lst))
    •     (setq i (1+ i))
    •   )
    •   (princ "\n 程序共用时")
    •   (princ (rtos (* (- (getvar "TDUSRTIMER") t0) 86400) 2 4))
    •   (princ "秒")
    • )
    • ;;测试------------12秒
    • (defun c:tt2 ()
    •   (setq t0 (getvar "TDUSRTIMER"))
    •   (setq lst (list "1" "2" "3" "4" "5") i 1)
    •   (while (< i 90000)
    •     (princ (nth 4 lst))
    •     (setq i (1+ i))
    •   )
    •   (princ "\n 程序共用时")
    •   (princ (rtos (* (- (getvar "TDUSRTIMER") t0) 86400) 2 4))
    •   (princ "秒")
    • )
    • ;;测试------------12秒   与nth 相同
    • (defun c:tt3 ()
    •   (setq t0 (getvar "TDUSRTIMER"))
    •   (setq lst (list "1" "2" "3" "4" "5") i 1)
    •   (while (< i 90000)
    •     (princ (cadr lst))
    •     (setq i (1+ i))
    •   )
    •   (princ "\n 程序共用时")
    •   (princ (rtos (* (- (getvar "TDUSRTIMER") t0) 86400) 2 4))
    •   (princ "秒")
    • )
    • ;;测试------------13秒   
    • (defun c:tt4 ()
    •   (setq t0 (getvar "TDUSRTIMER"))
    •   (setq lst (list "1" "2" "3" "4" "5") i 1)
    •   (while (< i 90000)
    •     (princ (cadddr lst))
    •     (setq i (1+ i))
    •   )
    •   (princ "\n 程序共用时")
    •   (princ (rtos (* (- (getvar "TDUSRTIMER") t0) 86400) 2 4))
    •   (princ "秒")
    • )
  • 结论:  还没有nth 快,失败了。。。。。。。无语
    lisp 快慢顺序测试为: car < cadr < caddr < cadddr
  • 对这一结论严重怀疑,不应该是cadddr < caddr < cadr < car 吗?


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
 楼主| 发表于 2021-8-17 07:21 | 显示全部楼层
本帖最后由 尘缘一生 于 2021-8-17 08:07 编辑
baitang36 发表于 2021-8-17 06:45
lisp的表在内存中的数据结构是cons,也就是一个链表。每个节点包含下一节点的地址和本节点的内容。表的每个 ...

奥,有道理,我重新试试,
  • ;;nth替代函数--------(一级)----------
  • (defun nnth (i lst / k)
  •   (setq loop t k 0)
  •   (while loop
  •     (setq numlis (car lst))
  •     (if (/= k i)
  •       (setq lst (cdr lst) k (1+ k))
  •       (setq loop nil)
  •     )
  •   )
  •   numlis
  • )
  • ;测试-------12秒
  • (defun c:tt1 ()
  •   (setq t0 (getvar "TDUSRTIMER"))
  •   (setq lst (list "1" "2" "3" "4" "5") i 1)
  •   (while (< i 4400000)
  •     (nnth 4 lst)
  •     (setq i (1+ i))
  •   )
  •   (princ (strcat "\n 程序共用时" (rtos (* (- (getvar "TDUSRTIMER") t0) 86400) 2 4) "秒"))
  • )
  • ;;测试------------9秒
  • (defun c:tt2 ()
  •   (setq t0 (getvar "TDUSRTIMER"))
  •   (setq lst (list "1" "2" "3" "4" "5") i 1)
  •   (while (< i 20000000)
  •     (nth 4 lst)
  •     (setq i (1+ i))
  •   )
  •   (princ (strcat "\n 程序共用时" (rtos (* (- (getvar "TDUSRTIMER") t0) 86400) 2 4) "秒"))
  • )
  • ;;测试------------7秒   
  • (defun c:tt3 ()
  •   (setq t0 (getvar "TDUSRTIMER"))
  •   (setq lst (list "1" "2" "3" "4" "5") i 1)
  •   (while (< i 20000000)
  •     (cadr lst)
  •     (setq i (1+ i))
  •   )
  •   (princ (strcat "\n 程序共用时" (rtos (* (- (getvar "TDUSRTIMER") t0) 86400) 2 4) "秒"))
  • )
  • ;;测试------------9秒   
  • (defun c:tt4 ()
  •   (setq t0 (getvar "TDUSRTIMER"))
  •   (setq lst (list "1" "2" "3" "4" "5") i 1)
  •   (while (< i 20000000)
  •     (cadddr lst)
  •     (setq i (1+ i))
  •   )
  •   (princ (strcat "\n 程序共用时" (rtos (* (- (getvar "TDUSRTIMER") t0) 86400) 2 4) "秒"))
  • )
  • ;;; 结论:取单独字符   速度  car < cadr < caddr < cadddr < nth

发表于 2021-8-17 16:43 | 显示全部楼层
不用测了,组合car cdr比nth快的多
发表于 2021-8-17 21:30 来自手机 | 显示全部楼层
晓东上有现成的函数,跟老猫方法同
发表于 2021-8-17 22:47 | 显示全部楼层
tryhi 发表于 2021-8-17 21:56
不对吧,我觉得无法写出一个能替代nth的函数,只有在某些特定情况的算法可以用car cdr来代替nth,但是想 ...

循环几万次为了读一个值的程序实际应用没有这么写的。
楼主问的也是对整个表的读取遍历,只是楼主的代码测试的不太对,效率损失了。
正确的测试方式是对一个大表进行循环读取,查看耗时。

;nth方式遍历表
(defun c:t1 (/ i lstx)
        (setq lstx nil i 0)
        (repeat 10000 (setq i(1+ i) lstx(cons i lstx)));;生成100万个元素的表
        (setq t0 (getvar "TDUSRTIMER"));计时开始
                (setq i 0)
        (repeat (length lstx)
             (setq x (nth i lstx))
                         (setq i (1+ i))
        )
        (princ (strcat "\n 程序共用时" (rtos (* (- (getvar "TDUSRTIMER") t0) 86400) 2 4) "秒"));计时结束
)
;car cdr 方式遍历表
(defun c:t2 (/ i lstx)
        (setq lstx nil i 0)
        (repeat 10000 (setq i(1+ i) lstx(cons i lstx)));;生成100万个元素的表
        (setq t0 (getvar "TDUSRTIMER"));计时开始
        (while lstx
                        (setq x (car lstx))
                        (setq lstx (cdr lstx))
                )
        (princ (strcat "\n 程序共用时" (rtos (* (- (getvar "TDUSRTIMER") t0) 86400) 2 4) "秒"));计时结束
)

我电脑不够快,100万数据太久,所以用1万数据测试。
命令: t1
程序共用时0.1740秒"\n 程序共用时0.1740秒"
命令:
命令: t2
程序共用时0.0010秒"\n 程序共用时0.0010秒"


nth增加序号有损失效率,所以组合car cdr比nth快的多
发表于 2021-8-17 22:50 | 显示全部楼层
不死猫 发表于 2021-8-17 22:47
循环几万次为了读一个值的程序实际应用没有这么写的。
楼主问的也是对整个表的读取遍历,只是楼主的代码 ...

原来如此,因为我看楼主的标题写的是“替代nth”,所以指出nth不具备完全可替代性,在遍历这个问题上我的看法倒是跟猫老师一致
发表于 2021-8-17 22:52 | 显示全部楼层
大佬们玩的好深,不用太多,就取二三十个元素的时候,不用nth 能有啥好法子吗,总不能一堆dddd吧
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-4-20 08:40 , Processed in 0.303689 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表