5

在这个问题中,我有三个(结构相同的)列表。两个有所有数字,另一个用 填充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))))

问题是这个函数没有破坏性。如何使此功能具有破坏性?


好的,我知道我可以使用 anapply来做到这一点,但是为了将来或切线的目的,有没有办法使用循环来做同样的事情?


我决定求助于我的倒数第二个解决方案;使用列表长度来横向列表。

(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))
4

3 回答 3

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)))

附录

这是另一种使用地图而不是循环的方式:

(defun add-two-lists (list1 list2 list3)
  (mapl #'(lambda (cl al bl) (rplaca cl (+ (car al) (car bl))))
    list3 list1 list2))
于 2012-06-12T16:54:38.590 回答
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,但这是我在 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
于 2012-06-12T17:21:19.890 回答
3

Common Lisp 为此提供了一个函数:MAP-INTO

于 2012-06-12T20:30:04.103 回答