消除球拍列表中元素的最后一次出现

eliminate the last occurrence of an element in a list in 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-without 递归调用,而不使用冗余反转。

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

您会注意到 (car lst) 是列表的极端情况。 如果它是一个列表,我们必须检查它是否出现 el.

重要 是我们在该列表上调用 last-without 而不是 remove-last-rec。这是因为在开始调用 (reverse (remove-last-rec (reverse list))) 中,嵌套列表未被原始 reverse 反转。

如果您调用 remove-last-rec,结果中嵌套列表的顺序将是错误的。我建议您自己尝试(错误地调用 remove-last-rec),尝试列出您认为可能会失败的列表非常有启发性。

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

(last-without '(a (b c a c) b) 'c)

EDIT :极端情况需要显式测试以检查 (last-without nested el) returns 是否为相同的嵌套列表。如果不是,则嵌套列表 nested 中最后一次出现的 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))

辅助函数执行元素的删除和 returns 两个值:一个布尔值,如果元素已被删除,则为 #t,以及结果列表。因此,在检查列表不为空后,它将自身应用于列表的其余部分,返回两个值。如果 removed#t,则不必执行任何其他操作,并且会重建列表。否则函数 必须 仍然删除元素,因此它检查它是否等于 lst 的第一个元素并在这种情况下删除它,否则,如果第一个元素是一个列表,在上面自称。

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

尝试

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

其中 (remove-first xs x) 将删除 xs 中第一次出现的 x