Common lisp Lisp-循环列表并替换值
在这个问题中,我有三个(结构相同的)列表。其中两个包含所有数字,另一个填充有Common lisp Lisp-循环列表并替换值,common-lisp,Common Lisp,在这个问题中,我有三个(结构相同的)列表。其中两个包含所有数字,另一个填充有nil。我试图用两个列表中的对应值相加来替换空列表中的对应值。到目前为止,我使用的是一个循环,并使用setf替换该值 (定义添加两个列表(列表1列表2列表3) (列表1中的循环 对于清单2中的b 对于清单3中的c,请执行以下操作 (setf c(ab)) 问题是这个功能没有破坏性。如何使此函数具有破坏性 好的,我知道我可以使用apply来做这件事,但是为了将来或相切的目的,有没有办法使用循环来做同样的事情 我决定采
nil
。我试图用两个列表中的对应值相加来替换空列表中的对应值。到目前为止,我使用的是一个循环,并使用setf
替换该值
(定义添加两个列表(列表1列表2列表3)
(列表1中的循环
对于清单2中的b
对于清单3中的c,请执行以下操作
(setf c(ab))
问题是这个功能没有破坏性。如何使此函数具有破坏性
好的,我知道我可以使用
apply
来做这件事,但是为了将来或相切的目的,有没有办法使用循环来做同样的事情
我决定采用倒数第二种解决办法;使用列表长度横穿列表。 这里有一个方法:
(defun add-two-lists (list1 list2 list3)
(loop for a in list1
for b in list2
for c on list3 do
(rplaca c (+ a b)))
附录
以下是使用映射而不是循环的另一种方法:
(defun add-two-lists (list1 list2 list3)
(mapl #'(lambda (cl al bl) (rplaca cl (+ (car al) (car bl))))
list3 list1 list2))
还有一种不用循环就可以做同样事情的方法(尽管在概念上很相似) 编辑
(defun add-two-lists (a b c &optional (d c))
(if a
(add-two-lists
(cdr a) (cdr b)
(cdr (rplaca c (+ (car a) (car b)))) d) d))
(time
(dotimes (i 1e6)
(add-two-lists '(1 2 3 4 5)
'(1 2 3 4 5)
'(nil nil nil nil nil))))
;; Evaluation took:
;; 0.077 seconds of real time
;; 0.076004 seconds of total run time (0.076004 user, 0.000000 system)
;; 98.70% CPU
;; 214,723,476 processor cycles
;; 0 bytes consed
(defun add-two-lists-1 (list1 list2 list3)
(loop for a in list1
for b in list2
for c on list3 do
(rplaca c (+ a b))))
(time
(dotimes (i 1e6)
(add-two-lists-1 '(1 2 3 4 5)
'(1 2 3 4 5)
'(nil nil nil nil nil))))
;; Evaluation took:
;; 0.060 seconds of real time
;; 0.060004 seconds of total run time (0.060004 user, 0.000000 system)
;; 100.00% CPU
;; 169,395,444 processor cycles
;; 0 bytes consed
编辑2
但是请注意优化的版本行为。同样,可能是YMMV,但这是我在64位Debian和SBCL上得到的
(defun add-two-lists (a b c &optional (d c))
(declare (optimize (speed 3) (safety 0)))
(declare (type list a b c d))
(if a
(add-two-lists
(cdr a) (cdr b)
(cdr (rplaca
c
(the fixnum
(+ (the fixnum (car a))
(the fixnum (car b)))))) d) d))
(time
(dotimes (i 1e6)
(add-two-lists '(1 2 3 4 5)
'(1 2 3 4 5)
'(nil nil nil nil nil))))
;; Evaluation took:
;; 0.041 seconds of real time
;; 0.040002 seconds of total run time (0.040002 user, 0.000000 system)
;; 97.56% CPU
;; 114,176,175 processor cycles
;; 0 bytes consed
(defun add-two-lists-1 (list1 list2 list3)
(declare (optimize (speed 3) (safety 0)))
(loop for a fixnum in list1
for b fixnum in list2
for c cons on list3 do
(rplaca c (the fixnum (+ a b)))))
(time
(dotimes (i 1e6)
(add-two-lists-1 '(1 2 3 4 5)
'(1 2 3 4 5)
'(nil nil nil nil nil))))
;; Evaluation took:
;; 0.040 seconds of real time
;; 0.040003 seconds of total run time (0.040003 user, 0.000000 system)
;; 100.00% CPU
;; 112,032,123 processor cycles
;; 0 bytes consed
Common Lisp为此提供了一个函数:。我最喜欢的制作破坏性函数的方法:我用宏伟的愿景填充它,说服它释放愤怒,让仇恨流过它。它通常是有效的,除非有一个子函数把它带回到光明的一面。使用NTH是最糟糕的方法。@SomeKittens Awesome,man:Dis
rplaca
common lisp的一部分?它与setf有何不同?是的,rplaca是公共Lisp的一部分(setf在修改的地方是cons的car时使用rplaca):--你可以说(setf(car c)…)而不是(rplaca c…),我认为这个递归解决方案是最后的选择。在这种情况下,我担心速度,所以我犹豫是否选择递归解决方案而不是(可能的,尚未找到的)迭代解决方案。作为比较,您知道更新的代码是比您的函数慢还是快?几乎不需要向代码中添加类型。如果你做得对,大多数列表处理都“足够快”。还请注意,在大多数Lisp编译器中,这将生成SAFETY=0的不安全代码。这太糟糕了。不幸的是,映射到
无法处理嵌套列表,这正是我要处理的。(我知道我上面的代码不考虑嵌套列表,但我已将其扩展为我文件中的递归函数)如果您知道我可以利用映射到
到嵌套列表的方法,请告诉我。
(defun add-two-lists (a b c &optional (d c))
(if a
(add-two-lists
(cdr a) (cdr b)
(cdr (rplaca c (+ (car a) (car b)))) d) d))
(time
(dotimes (i 1e6)
(add-two-lists '(1 2 3 4 5)
'(1 2 3 4 5)
'(nil nil nil nil nil))))
;; Evaluation took:
;; 0.077 seconds of real time
;; 0.076004 seconds of total run time (0.076004 user, 0.000000 system)
;; 98.70% CPU
;; 214,723,476 processor cycles
;; 0 bytes consed
(defun add-two-lists-1 (list1 list2 list3)
(loop for a in list1
for b in list2
for c on list3 do
(rplaca c (+ a b))))
(time
(dotimes (i 1e6)
(add-two-lists-1 '(1 2 3 4 5)
'(1 2 3 4 5)
'(nil nil nil nil nil))))
;; Evaluation took:
;; 0.060 seconds of real time
;; 0.060004 seconds of total run time (0.060004 user, 0.000000 system)
;; 100.00% CPU
;; 169,395,444 processor cycles
;; 0 bytes consed
(defun add-two-lists (a b c &optional (d c))
(declare (optimize (speed 3) (safety 0)))
(declare (type list a b c d))
(if a
(add-two-lists
(cdr a) (cdr b)
(cdr (rplaca
c
(the fixnum
(+ (the fixnum (car a))
(the fixnum (car b)))))) d) d))
(time
(dotimes (i 1e6)
(add-two-lists '(1 2 3 4 5)
'(1 2 3 4 5)
'(nil nil nil nil nil))))
;; Evaluation took:
;; 0.041 seconds of real time
;; 0.040002 seconds of total run time (0.040002 user, 0.000000 system)
;; 97.56% CPU
;; 114,176,175 processor cycles
;; 0 bytes consed
(defun add-two-lists-1 (list1 list2 list3)
(declare (optimize (speed 3) (safety 0)))
(loop for a fixnum in list1
for b fixnum in list2
for c cons on list3 do
(rplaca c (the fixnum (+ a b)))))
(time
(dotimes (i 1e6)
(add-two-lists-1 '(1 2 3 4 5)
'(1 2 3 4 5)
'(nil nil nil nil nil))))
;; Evaluation took:
;; 0.040 seconds of real time
;; 0.040003 seconds of total run time (0.040003 user, 0.000000 system)
;; 100.00% CPU
;; 112,032,123 processor cycles
;; 0 bytes consed