List 消除racket中列表中元素的最后一次出现

List 消除racket中列表中元素的最后一次出现,list,recursion,scheme,racket,List,Recursion,Scheme,Racket,我只是想知道,我能不能在racket中创建一个函数来消除列表中最后出现的元素,例如 >(last-without '(a b a (c e) d) 'e) = (a b a (c) d) >(last-without '(p q p (r p) q e p r) 'p) = (p q p (r p) q e r) 这也可以通过定义嵌套列表的成员资格测试来实现,方法是泛化内置成员,该成员可用于设置last,而无需递归调用,也无需使用冗余反向 (defin

我只是想知道,我能不能在racket中创建一个函数来消除列表中最后出现的元素,例如

>(last-without   '(a b  a  (c e) d)    'e)  =  (a b a (c) d)
>(last-without   '(p q  p (r p) q e p r)   'p) = (p q  p (r p) q e r)
这也可以通过定义嵌套列表的成员资格测试来实现,方法是泛化内置成员,该成员可用于设置last,而无需递归调用,也无需使用冗余反向

(define (last-without list el)
  (define (remove-last-rec lst)
    (cond ((null? lst) '())
          ((equal? (car lst) el) (cdr lst))
          ; Corner case below, if car is a list, we also have to check it for occurences of el
          ((list? (car lst)) (let* ((nested (car lst))
                                    (rest (cdr lst))
                                    (nested-res (last-without nested el)))
                               (if (equal? nested nested-res)
                                   (cons nested-res (remove-last-rec rest)); el did not occur in nested list
                                   (cons nested-res rest)))) ; We did removed it, not remove it from cdr anymore, instead just cons the unchanged cdr.
          (else (cons (car lst) (remove-last-rec (cdr lst))))))

  (reverse ; Reverse filtered list back to original order
   (remove-last-rec 
    (reverse list))))
您会注意到拐角处的情况,其中carlst是一个列表。 如果它是一个列表,我们必须检查它是否出现el

重要的是,我们调用该列表上的last without,而不是remove-last-rec。这是因为嵌套列表没有被start调用reverse remove last rec reverse list中的原始reverse反转

如果调用remove last rec,则嵌套列表的顺序将在结果中出错。我建议你试着用一个错误的调用来删除最后一个rec,尝试列出你认为可能失败的列表是非常有益的

如果你找不到,试试这个。 它不会输出您所期望的内容

(last-without '(a (b c a c) b) 'c)
编辑:角落案例需要显式测试,以检查last With nested el是否返回相同的嵌套列表。如果没有,嵌套列表中最后出现的el已被过滤掉,我们不再需要过滤rest中最后出现的el。

这里有一个解决方案:

(define (last-without lst el)
  (define (aux lst)  ; returns two values: removed and result
    (if (null? lst)
        (values #f '())
        (let-values (((removed result) (aux (cdr lst))))
                (if removed
                    (values removed (cons (car lst) result))
                    (cond ((equal? (car lst) el) (values #t result))
                          ((list? (car lst))
                           (let-values (((removed-from-car result-of-car) (aux (car lst))))
                             (values removed-from-car (cons result-of-car result))))
                          (else (values #f (cons (car lst) result))))))))
  (let-values (((removed result) (aux lst)))
    result))
辅助函数执行元素的删除并返回两个值:一个布尔值(如果元素已删除,则为t)和结果列表。因此,在检查列表是否为空后,它将自身应用于列表的其余部分,并返回两个值。如果removed为t,则不必执行其他操作,列表将重新生成。否则,函数仍必须删除该元素,因此它会检查该元素是否等于lst的第一个元素,并在本例中删除该元素,否则,如果第一个元素是列表,则会对其调用自身

最后请注意,标题在某种程度上具有误导性:该函数不会从列表中删除最后一个el元素,而是删除树中最右边的el元素。

试试看

(define (remove-last xs)
  (reverse (remove-first (reverse xs) x)))

其中remove first xs x将删除xs中第一个出现的x。

在类似last的情况下,如果没有'p'p,您的解决方案将返回p。这对嵌套列表不起作用,是吗?当在remove first过程中遇到嵌套列表时,不会将其反转,因此删除嵌套列表中的第一个而不是最后一个。仅当remove first在下降到子树时调用remove last时,才会执行此操作。但目的是让OP自己先编写remove。