取代旧的第n次出现

时间:2018-03-29 17:29:08

标签: scheme racket r5rs

我正在尝试将每个第n次出现的new替换为lst作为列表,可以是原子列表或列表列表。当lst是列表列表时,我无法用new取代旧的第n次出现。

(define (replace lst n old new)
  (cond ((null? lst) '())
        ((and (= n 1) (eq? (car lst) old)) (cons new (cdr lst)))
        ((not (atom? (car lst)))
          (cons (replace (car lst) n old new) (replace (cdr lst) n old new)))
        ((and (atom? (car lst)) (eq? (car lst) old)) (cons old (replace (cdr lst) (- n 1) old new)))
        (else (cons (car lst) (replace (cdr lst) n old new)))))

调用上面的函数

(replace '(a b c a d e f g a t y a g) '3 'a 'o)

给我(例如,g),但是当我输入列表列表时,我无法获得正确的输出

(replace '((a a) b c a d e f g a t y a g) '3 'a 'o)

这可能是因为当我的函数进入列表(a a)时,我的n计数器会被递减。有没有办法通过n计数器?

2 个答案:

答案 0 :(得分:1)

使用新值替换旧值时,将返回(cons new (cdr lst))。 问题是你不能替换(cdr lst)中剩余的任何事件。

尝试(cons new (replace (cdr lst) original-n old new )之类的内容。 您将需要原始n,因此您可以执行以下操作:

(define (replace lst n old new)
  (replace-helper lst n n old new))

(define replace-helper lst original-n n old new)
    ...your existing solution where replace has been
       renamed to replace-helper...))

答案 1 :(得分:1)

为了将当前n从处理car传递到cdr,您需要让帮助程序返回结果和当前n。 作为一个例子,这里有一个用项目号替换树中每个匹配的东西:

(define (replace-with-index haystack needle)
  (define  (result n value) value)
  (let loop ((lst haystack) (n 0) (k result))
    (if (null? lst)
        (k n '())
        (let ((a (car lst)) (d (cdr lst)) (nn (+ n 1)))
          (cond ((equal? needle a)
                 (loop d nn (lambda (cn r) (k cn (cons n r)))))
                ((not (pair? a))
                 (loop d nn (lambda (cn r) (k cn (cons a r)))))
                (else
                 (loop a n (lambda (cn ar)
                             (loop d cn (lambda (cn dr)
                                          (k cn (cons ar dr))))))))))))

(replace-with-index '(a (a b (h e)) (c d (h e) l l)) '(h e)) 
; ==> (a (a b 3) (c d 6 l l))

该技术称为延续传递方式。您可以在不返回当前n和结果:

的情况下执行此操作
(define (replace-with-index haystack needle)  
  (define (helper lst n)
    (if (null? lst)
        (values n '())
        (let ((a (car lst)) (d (cdr lst)) (nn (+ n 1)))
          (cond ((equal? needle a)
                 (let-values ([(cn r) (helper d nn)])
                   (values cn (cons n r))))
                ((not (pair? a))
                 (let-values ([(cn r) (helper d nn)])
                   (values cn (cons a r))))
                (else
                 (let*-values ([(an ar) (helper a n)]
                               [(dn dr) (helper d an)])
                   (values dn (cons ar dr))))))))
  (let-values ([(n r) (helper haystack 0)])
    r))

这与CPS版本的区别仅在于风格。由于许多Scheme实现实际上将代码转换为CPS,因此执行的代码几乎相同。作为最后一个例子,我删除了多个值,并以cons的形式使用了封装。

(define (replace-with-index haystack needle)
  ;; abstraction
  (define nrbox cons)
  (define nrbox-n car)
  (define nrbox-r cdr)

  (define (helper lst n)
    (if (null? lst)
        (cons n '())
        (let ((a (car lst)) (d (cdr lst)) (nn (+ n 1)))
          (cond ((equal? needle a)
                 (let ((nr (helper d nn)))
                   (nrbox (nrbox-n nr) (cons n (nrbox-r nr)))))
                ((not (pair? a))
                 (let ((nr (helper d nn)))
                   (nrbox (nrbox-n nr) (cons a (nrbox-r nr)))))
                (else
                 (let* ((anr (helper a n))
                        (dnr (helper d (nrbox-n anr))))
                   (nrbox (nrbox-n dnr) (cons (nrbox-r anr) (nrbox-r dnr)))))))))
  (nrbox-r (helper haystack 0)))

基本上这个cons有很多临时对,而多值和CPS版本保留了堆栈上的值。因此,差异在于性能。在抽象的形式中,它们是完全相同的代码。