修复删除元素的函数 [Common Lisp]

fix the function which removes elments [Common Lisp]

任务是:对于给定的元素列表和 X 元素,如果不等于 X,则删除 X 之后的元素。示例:(a 8 2 a a 5 a) X=a,期望 (a 2 a a a ). 我有删除元素 before X 的代码,所以它给了我 (a 8 a a a)。我该如何解决?

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

我认为您使用递归算法是正确的。我认为该算法作为 tail-optimised 递归效果更好。你拿一个 in-list 和一个 X,然后建立一个 out-list。输出是相反的,所以最后需要应用reverse,因此:

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

至于non-tail算法,我觉得是这样的:

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

因此,如果第一个元素是n而下一个元素不是n,则在算法的前面添加n,但跳过cddr下一个元素。否则,将第一个元素添加到算法前面,不跳过cdr.

注意:既然你已经根据 X 定义了问题,我认为这应该是你的参数之一,而不是 n

您可以在 loop 中使用 for on 子句的解构:

(defun purgatory (list x)
  (cons (first list)
        (loop :for (a b) :on list
              :unless (and (eql a x)
                           (not (eql b x)))
              :collect b)))