替换第 n 次出现的 old
Replacing every nth occurence of old
我正在尝试用 lst 替换第 n 次出现的 old 和 new,作为一个列表,可以是原子列表或列表列表。当 lst 是列表列表时,我无法用新出现的第 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)
给我 (a b c a d e f g o t y a g),但是当我输入一个列表列表时,我无法得到正确的输出
(replace '((a a) b c a d e f g a t y a g) '3 'a 'o)
这可能是因为当我的函数进入列表 (a a) 时,我递减的 n 计数器没有返回。有没有办法通过n计数器?
当您用新值替换旧值时,您 return (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...))
为了将当前 n
从处理 car
传递到 cdr
,您需要让助手 return 同时获得结果和当前 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))
这种技术称为延续传球风格。你可以在没有 return 当前 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 版本将值保存在堆栈中。因此,差异在于性能。在抽象形式上,它们是完全相同的代码。
我正在尝试用 lst 替换第 n 次出现的 old 和 new,作为一个列表,可以是原子列表或列表列表。当 lst 是列表列表时,我无法用新出现的第 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)
给我 (a b c a d e f g o t y a g),但是当我输入一个列表列表时,我无法得到正确的输出
(replace '((a a) b c a d e f g a t y a g) '3 'a 'o)
这可能是因为当我的函数进入列表 (a a) 时,我递减的 n 计数器没有返回。有没有办法通过n计数器?
当您用新值替换旧值时,您 return (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...))
为了将当前 n
从处理 car
传递到 cdr
,您需要让助手 return 同时获得结果和当前 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))
这种技术称为延续传球风格。你可以在没有 return 当前 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 版本将值保存在堆栈中。因此,差异在于性能。在抽象形式上,它们是完全相同的代码。