Search code examples
common-lisp

fix the function which removes elments [Common Lisp]


The task is: for given list of elements and X element, remove an element after X if it is not equal to X. Example: (a 8 2 a a 5 a) X=a, expecting (a 2 a a a). I have code that removes an element before X, so it gives me (a 8 a a a) instead. How do I fix it?

(defun purgatory (n w)
  (cond ((null w) nil)
        ((and (eq (cadr w) n) (not (eq (car w) (cadr w)))) (purgatory n (cdr w)))
        ((cons (car w) (purgatory n (cdr w))))))

Solution

  • I think you are on the right lines with a recursive algorithm. I think that the algorithm works better as a tail-optimised recursion. You take an in-list and an X, and build up an out-list. The output is reversed, and so reverse needs to be applied at the end, thus:

    (defparameter my-list '(a 8 2 a a 5 a))
    
    (defun remove-after (in-list X &optional (out-list '()) (last '()))
      (if (null in-list)
        (reverse out-list)
        (if (and (eql last X) (not (eql (car in-list) X)))
           (remove-after (cdr in-list) X out-list (car in-list)) 
           (remove-after (cdr in-list) X (cons (car in-list) out-list) (car in-list))
        )))
    
     ; (A 2 A A A)
    

    As for the non-tail algorithm, I think this does it:

    (defun purgatory (n w)
      (cond ((null w) nil)
            ((and (eq (car w) n) (not (eq n (cadr w)))) (cons (car w) (purgatory n (cddr w))))
            (t (cons (car w) (purgatory n (cdr w))))
    ))
    
    ; (A 2 A A A)
    

    So, if the first element is n and the next is not n, then add n at the front of the algorithm, but skip cddr the next element. Otherwise, add the first element to the front of the algorithm, no skip cdr.

    NB: since you've defined the problem in terms of X, I think this should be one of your parameters, not n