在这个问题中,我有三个(结构相同的)列表。两个包含所有数字,另一个包含nil
。我试图通过添加两个列表中的相应值来替换空列表中的相应值。到目前为止我使用循环并使用setf
来替换值。
(defun add-two-lists (list1 list2 list3)
(loop for a in list1
for b in list2
for c in list3 do
(setf c (+ a b))))
问题是这个功能没有破坏性。如何使这个功能具有破坏性?
好的,我知道我可以使用apply
来做这件事,但是为了将来或相切的目的,有没有办法使用循环来做同样的事情?
我决定求助于我的倒数第二个解决方案;使用list-length来横向列表。
(defun add-two-lists (list1 list2 list3)
(loop for x from 0 to (- (list-length list1) 1) do
(setf (nth x list3) (+ (nth x list1) (nth x list2))))
(values list3))
答案 0 :(得分:4)
这是一种方式:
(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)))
附录
这是使用map而不是loop的另一种方式:
(defun add-two-lists (list1 list2 list3)
(mapl #'(lambda (cl al bl) (rplaca cl (+ (car al) (car bl))))
list3 list1 list2))
答案 1 :(得分:3)
另一种在不使用循环的情况下做同样事情的方法(虽然它在概念上相似)
(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))
(add-two-lists '(1 2 3 4 5) '(1 2 3 4 5) '(nil nil nil nil nil))
修改强>
(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,但这是我用SBCL获得的64位Debian。
(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
答案 2 :(得分:3)
Common Lisp提供了一个函数:MAP-INTO。