我正在尝试将每个第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计数器?
答案 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版本保留了堆栈上的值。因此,差异在于性能。在抽象的形式中,它们是完全相同的代码。