【问题标题】:Replacing every nth occurence of old替换每第 n 次出现的 old
【发布时间】:2018-09-08 18:15:42
【问题描述】:

我试图用 lst 替换每第 n 次出现的 old 和 new 作为一个列表,可以是原子列表或列表列表。当 lst 是列表列表时,我无法将第 n 个 old 替换为 new。

(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) 时,我递减的 n 计数器没有返回。有没有办法通过n计数器?

【问题讨论】:

    标签: scheme racket r5rs


    【解决方案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 版本将值保留在堆栈上。因此,区别在于性能。在抽象形式上,它们是完全相同的代码。

    【讨论】:

      【解决方案2】:

      当您用新值替换旧值时,您会返回 (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...))
      

      【讨论】:

        猜你喜欢
        • 2018-08-11
        • 2018-03-24
        • 1970-01-01
        • 2011-08-17
        • 1970-01-01
        • 2016-12-02
        • 2015-06-23
        • 2011-03-05
        • 2021-12-19
        相关资源
        最近更新 更多