Recursing Through Nested List LISP

2019-09-06 10:54发布

问题:

How would I recurse through nested lists?

For example, given: '((A 1 2) (B 3 4))

How would I add 2 to the second element in each nested sublist?

(defun get-p0 (points)
    (loop for x from 0 to
            (-  (list-length    points) 1) do
                (+ 2 (cadr (nth x points)))
    )
)

I'm not really sure why (get-p0 '((A 1 2) (B 3 4))) returns NIL.

回答1:

I'd go with something like this:

(loop for (letter x y) in '((A 1 2) (B 3 4))
     collect (list letter (+ 2 x) y))

The reason: it's shorter and you don't measure the length of the list in order to iterate over it (why would you do that?)



回答2:

Since you ask for a recursive solution:

(defun get-p0 (lst &optional (n 0))
  (if (null lst) 
      nil
      (let ((elt1 (first lst)) (eltn (cdr lst)))
        (if (listp elt1)
             (cons (get-p0 elt1) (get-p0 eltn))
             (cons (if (= n 1) (+ elt1 2) elt1) (get-p0 eltn (+ n 1)))))))

so

? (get-p0 '((A 1 2) (B 3 4)))
((A 3 2) (B 5 4))

and it recurses further down if necessary:

? (get-p0 '((A 0 2) ((B -4 4) (C 10 4))))
((A 2 2) ((B -2 4) (C 12 4)))


回答3:

The way you put it, you can consider the problem as a basic recursion pattern: you go through a list using recursion or iteration (mapcar, reduce, etc.; dolist, loop, etc.) and apply a function to its entries. Here is a functional solution:

(defun get-p0 (points)
  (mapcar #'add-2 points))

where the auxiliary function can be defined as follows:

(defun add-2 (lst)
  "Add 2 to the 2nd item"
  (let ((res '()))
    (do ((l lst (cdr l))
         (i 1 (1+ i)))
      ((null l) (nreverse res))
      (push (if (= 2 i)
              (+ 2 (car l))
              (car l))
            res))))


回答4:

As written your 'loop' use does not return anything; thus NIL is returned. As is your code is simply iterating over x and computing something; that something isn't stored anywhere.

So, how to get your desired result? Assuming you are willing to modify each point in points, this should work:

(defun get-p0 (points)
  (loop for x from 0 to (- (list-length points) 1) do
    (let ((point (nth x points)))
      (setf (cadr point) (+ 2 (cadr point)))))
   points)