Lisp - Scroll and replace values

In this task, I have three (equally structured) lists. Two have all numbers, and the rest are filled with nil . I am trying to replace the corresponding value in an empty list with the addition of the corresponding values ​​from the two lists. That I still use a loop 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 (+ ab)))) 

The problem is that this feature is not destructive. How to make this function destructive?


Well, I know that I could use apply for this, but for future or tangential purposes, is there a way to use a loop to do the same?


I decided to resort to my penultimate decision; use list length to scroll through 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)) 
+4
source share
3 answers

Another way to do the same without using a loop (although it is conceptually similar)

 (defun add-two-lists (abc &optional (dc)) (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 (abc &optional (dc)) (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 (+ ab)))) (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 pay attention to the optimized version behavior. Maybe, again, YMMV, but this is what I get on 64-bit Debian with SBCL.

 (defun add-two-lists (abc &optional (dc)) (declare (optimize (speed 3) (safety 0))) (declare (type list abcd)) (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 (+ ab))))) (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 
+3
source

Here is 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 (+ ab))) 

ADDITION

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

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

General Lisp provides a function for this: MAP-INTO .

+3
source

All Articles