MCPartington
MCPartington

Reputation: 13

Adding a value to the last index of a list (LISP)

I'm trying to add a given variable x to a list L. Both of which are parameters of the function ADDV. The code I have so far is as follows:

(defun addV(L x)
    (cond
        ((eq L nil)     nil)
        ((eq (cdr L) nil) (list(+(car L) x)))
        (+ x (first(last L)))
        (butlast L)
        (append L x) ) )

With the parameters

L = '(1 2 3 4)
x =  2

When the statement: (+ x (first(last L)))) is evaluated, it's value is 4. The final goal should be L = '(1 2 3 6)

I'm not sure what I'm doing wrong. Any help would be greatly appreciated. Thanks.

Upvotes: 1

Views: 247

Answers (2)

Joshua Taylor
Joshua Taylor

Reputation: 85843

If you can do this destructively, then you can use incf and last:

(defun increment-last (list x)
  (prog1 list ; return the list
    (incf (first (last list)) x)))

If you do need to make a new list, you'll have to walk to the end of the list to get to the last element. While you're doing that, you could keep track of the elements you've already seen (in reverse order) and efficiently use that reverse order list to construct the new list for you using nreconc:

(defun plus-last (list x)
  (do ((list list (rest list))
       (rhead '() (list* (first list) rhead)))
      ((endp (rest list))
       (nreconc rhead (list (+ x (first list)))))))
CL-USER> (plus-last '(1 2 3 4) 2)
(1 2 3 6)

If you're not so comfortable with do syntax, you could use a tail recursive function, too (which some Common Lisp implementations can optimize into a loop):

(defun plus-last (list x)
  (labels ((pl (list rhead)
             (if (endp (rest list))
                 (nreconc rhead (list (+ x (first list))))
                 (pl (rest list)
                     (list* (first list) rhead)))))
    (pl list '())))

You could also use loop, and express the logic pretty clearly:

(defun plus-last (list x)
  (loop for (a . b) on list       
     if (null b) collect (+ a x)
     else collect a))

This could also be done with maplist:

(defun plus-last (list x)
  (maplist (lambda (list)
             (if (endp (rest list))
                 (+ x (first list))
                 (first list)))
           list))

Upvotes: 2

Will Ness
Will Ness

Reputation: 71065

Your code is badly formatted. Re-indenting, we get

(defun addV(L x)
    (cond
        ((eq L nil)    
            nil)
        ((eq (cdr L) nil) 
            (list (+ (car L) x)))
        (+ 
            x 
            (first (last L)))
        (butlast
            L)
        (append
            L 
            x) ) )

do you see the problem now?

Since (not +) is NIL, the corresponding clause in the COND form is entered. Its body's forms (x and (first (last L))) are evaluated for effects, of which there are none. Then the last form's value is returned.

What you evidently wanted it to be, is

(defun addV (L x)
    (cond
        ((eq L nil)    
            nil)
        ((eq (cdr L) nil) 
            (list (+ (car L) x)))
        (T
            (append
                (butlast L)
                (list (+ x (first (last L))))))))

Coincidentally, the 2nd clause it completely unnecessary and may just be omitted, making it

(defun addV (L x)
    (if (not (null L))
      (append (butlast L)
              (list (+ x (first (last L)))))))

Upvotes: 2

Related Questions