Scheme DrRacket从列表末尾开始删除元素

Scheme DrRacket从列表末尾开始删除元素,scheme,racket,Scheme,Racket,我有删除元素第一次出现的代码 (define delete (lambda (a lst) (cond ((null? lst) (lst)) ((eq? (car lst) a) (cdr lst)) (else (cons (car lst) (delete a (cdr lst))))))) 现在,我希望它删除元素,但从列表的末尾开始,例如(delete 2'(2 5 4 2 6))将返回'(2 5 4

我有删除元素第一次出现的代码

(define delete
  (lambda (a lst)
    (cond
      ((null? lst) (lst))
      ((eq? (car lst) a) (cdr lst))
      (else (cons (car lst)
                  (delete a (cdr lst)))))))
现在,我希望它删除元素,但从列表的末尾开始,例如
(delete 2'(2 5 4 2 6))
将返回
'(2 5 4 6)
我不知道怎么做,因此非常感谢您的帮助。

当然,没问题:

#lang racket

(define (delete-last a lst) 
   (reverse (delete a (reverse lst))))

这是一项针对
foldr
的作业:

(define (remove-from-end v xs)
   (let ((flag #t))
     (foldr (lambda (x r)
               (if (and flag (equal? v x)) 
                     (begin (set! flag #f) 
                            r)
                     (cons x r)))
            '() xs)))
测试:

> (remove-from-end 2 '(2 5 4 2 6))
'(2 5 4 6)

这个答案不使用突变或多重循环。这可能与约翰克莱门斯在他的一篇评论中暗示的类似

这些特性不会使它比其他解决方案更好或更差。每一个实现都涉及到一个权衡,最好考虑一下这些因素,并意识到它们

(define (delete-last a lst)
  (define (loop lst return)
    (if (null? lst)
        (return null #t)
        (loop (cdr lst)
              (lambda (rest untouched?)
                (if (and untouched? (eq? a (car lst)))
                    (return rest #f)
                    (return (cons (car lst) rest) untouched?))))))
  (loop lst (lambda (result _) result)))

(delete-last 'a '(a b c a d e f g a h i a j k l))
;; '(a b c a d e f g a h i j k l)

... 虽然为了不伪造多个返回值,您可能需要CPS。我坚持双反转;相同的big-o运行时间。big-o是一个谣言。:)/开玩笑/很多2倍或3倍慢的东西都有相同的大O型。而且,封装良好的突变,真的有什么不对?当然,另一个选项是foldr结果的求和类型,将“中途”从一个变量切换到另一个变量。。。但这恰恰表达了国旗价值的转换,不是吗。如果我们根本不想要变异,那就让我们在语言中禁止它吧!在那之前。。。他们甚至在Haskell中也有。作为一个可执行规范,双反转是很好的。当然,对于真正与性能相关的应用程序来说,列表作为一个整体可能完全是错误的选择,那么清晰和简洁将赢得巨大的胜利。:)但心理体操也并非完全没有目的。最重要的是,玩得开心!嗯,是的,两次遍历就像我的版本一样,而John的是三次遍历。虽然也可以一次完成(使用“最坏”的突变,列表结构突变)。