Zchpyvr
Zchpyvr

Reputation: 1129

Lisp- Loop through list and replace values

In this problem, I have three (identically-structured) lists. Two have all numbers and the other is filled with nil. I'm trying to replace the corresponding value in the empty list with the addition of the corresponding values from the two lists. What I have so far utilizes a loop and uses setf to replace the value.

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

The problem is that this function is not being destructive. How do I make this function destructive?


Ok, I am aware I could use an apply to do this, but for future or tangent purposes, is there a way to use a loop to do the same thing?


I've decided to resort to my penultimate solution; use the list-length to transverse the lists.

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

Upvotes: 5

Views: 11592

Answers (3)

Rainer Joswig
Rainer Joswig

Reputation: 139261

Common Lisp provides a function for that: MAP-INTO.

Upvotes: 3

Doug Currie
Doug Currie

Reputation: 41180

Here's one way:

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

ADDENDUM

Here's another way that uses map instead of loop:

(defun add-two-lists (list1 list2 list3)
  (mapl #'(lambda (cl al bl) (rplaca cl (+ (car al) (car bl))))
    list3 list1 list2))

Upvotes: 4

user797257
user797257

Reputation:

Yet another way to do the same thing without using a loop (though it's conceptually similar)

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

EDIT

(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

EDIT 2

But notice the optimized version behavior. Possibly, again, YMMV, but this is what I get on 64-bit Debian with 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

Upvotes: 3

Related Questions