在Scheme中用数字替换字符串的累积递归

在Scheme中用数字替换字符串的累积递归,scheme,racket,accumulator,Scheme,Racket,Accumulator,问题如下: (define (abbreviate str) (local [(define str-lst (string->list str)) (define (count-duplicate lst char count) (cond [(empty? lst) count] [(equal? (first lst) char) (count-dup

问题如下:

(define (abbreviate str)
  (local [(define str-lst (string->list str))
          (define (count-duplicate lst char count)
            (cond
              [(empty? lst) count]
              [(equal? (first lst) char)
               (count-duplicate (rest lst)
                                (first lst)
                                (add1 count))]
              [else (count-duplicate (rest lst)
                                     (first lst)
                                     count)]))
          (define (build-string lst)
            (cond
              [(empty? lst) empty]
              [else (cons (first lst)
                          (cons (string->list (number->string 
                                         (count-duplicate (rest lst)
                                                          (first lst) 1)))
                          (build-string (rest lst))))]))]


    (build-string str-lst)))
  • 使用累积递归
  • 函数使用字符串并生成新字符串
  • 连续出现的每个字符都将替换为字母及其连续出现的次数
  • 示例:“hellooo”=>“hel2o3”
  • 这个问题是以大学为基础的
  • 我尝试了以下方法:

    (define (abbreviate str)
      (local [(define str-lst (string->list str))
              (define (count-duplicate lst char count)
                (cond
                  [(empty? lst) count]
                  [(equal? (first lst) char)
                   (count-duplicate (rest lst)
                                    (first lst)
                                    (add1 count))]
                  [else (count-duplicate (rest lst)
                                         (first lst)
                                         count)]))
              (define (build-string lst)
                (cond
                  [(empty? lst) empty]
                  [else (cons (first lst)
                              (cons (string->list (number->string 
                                             (count-duplicate (rest lst)
                                                              (first lst) 1)))
                              (build-string (rest lst))))]))]
    
    
        (build-string str-lst)))
    
    但我得到的结果是:

    (列表#\h(列表#\4)#\e(列表#\4)#\l(列表#\4)#\l(列表#\3)#\o(列表#\3)#\o(列表#\2)#\o(列表#\1))


    有什么帮助吗?

    首先对帮助程序进行单元测试,并给出一些提示:

    • 如果累积递归指的是尾部递归,那么请注意:
      buildstring
      不是尾部递归,必须完全重写
    • count duplicate
      没有达到预期效果-在递归调用中将
      (first lst)
      作为第二个参数传递是错误的
    • 你不是在数连续字符,你只是在数字符数
    • 输出列表的构造不正确-为什么总是将一个字符与其频率粘在一起?仅当字符连续复制时才执行此操作
    • 预期的输出是字符串,而不是字符列表。在某些情况下,您必须使用
      list->string
    • 此外,在某些时候,您必须将找到的字符数转换为一个字符,例如:
      3
      将变成
      \3
      。这是在末尾创建字符串所必需的
    有太多的错误,我的建议是从头开始,解决和测试子问题,然后再粘在一起的部分。但我将帮助您使用
    count duplicate
    过程,请注意,您只对给定字符的连续字符数感兴趣,这是正确的方法:

    (define (count-duplicate lst char count)
      (cond [(or (empty? lst) (not (char=? char (first lst))))
             count]
            [else
             (count-duplicate (rest lst) char (add1 count))]))
    
    您可以这样使用它:

    (count-duplicate (rest '(#\h #\e #\l #\l #\o)) #\h 1)
    => 1
    
    (count-duplicate (rest '(#\h #\h #\h #\l #\o)) #\h 1)
    => 3
    

    现在,您必须确保对于原始字符串中的每个当前字符,计算在列表的其余部分中找到的连续字符数,如果该数字大于
    1
    ,请以正确的方式构造输出列表。在找到重复字符后,不要忘记推进递归
    计数
    字符,否则将对同一字符进行多次计数!(提示:使用
    drop
    进行此操作)。

    此操作有效,不包括将最终列表转换回字符串:

    (define (abbreviate str)
      (let scanning ((list (string->list str))
                     (last #f)
                     (numb 1)
                     (rslt '()))
        (if (null? list)
            (reverse (if (= 1 numb) rslt (cons numb rslt)))  ; after reverse, make a string
            (let ((next (car list))
                  (rest (cdr list)))
              (if (equal? last next)
                  (scanning rest next (+ numb 1) rslt)
                  (scanning rest next 1
                            (cons next (if (= 1 numb) rslt (cons numb rslt)))))))))
    
    您可以看到,它是完全尾部递归的,并且在遍历字符串时累积结果

    > (abbreviate "22")
    (#\2 2)
    > (abbreviate "")
    ()
    > (abbreviate "hellllloo")
    (#\h #\e #\l 5 #\o 2)
    > (abbreviate "mississippi")
    (#\m #\i #\s 2 #\i #\s 2 #\i #\p 2 #\i)
    > (abbreviate "Noooooooooooooooooo way!")
    (#\N #\o 18 #\space #\w #\a #\y #\!)
    
    我假设,因为这是一个“大学水平”的问题,你实际上是在为一个班级学习球拍——我假设你在使用高级学生语言包

    我对累积递归的理解是程序使用了某种类型的内存。这是我研究的一个解决方案。它是问题的完整解决方案,与高级学生语言包完全兼容;代码有点笨重,但当然欢迎您对其进行改进

    ;; abbreviate : string -> string
    ;; consumes a string and produces a new string, with all occurences of
    ;; sequences of repeating characters reduced to 1 character and the 
    ;; number of times the character repeats
    ;; Example
    ;; (abbreviate "oooo) should be "o4"
    ;; (abbreviate "thiis iss a teesstt") should be "thi2s is2 a te2s2t2"
    ;; (abbreviate "magic") should be "magic"
    ;; Definitions:
    (define (abbreviate a-string)
      (local ((define memory empty)
              (define (count-dupes b)
                (cond ((empty? b) 0)
                      ((duplicate? b) (+ 1 (count-dupes (rest b))))
                      (else 0)))
              (define (skip-dupes c n)
                (cond ((= n 0) c)
                      ((empty? c) c)
                      (else (skip-dupes (rest c) (sub1 n)))))
              (define (duplicate? a)
                (equal? (first a) (first memory)))
              (define (load lst)
                (begin (set! memory (cons (first lst) memory)) (abbreviate-x (rest lst))))
              (define (abbreviate-x lst)
                (cond ((empty? lst) lst)
                      ((empty? memory) (cons (first lst) (load lst)))
                      ((duplicate? lst) (cons (+ 1 (count-dupes lst)) 
                                              (abbreviate-x 
                                                (skip-dupes lst (count-dupes lst)))))
                      (else (cons (first lst) (load lst)))))
              (define (string-adapt d)
                (cond ((empty? d) empty)
                      ((number? (first d)) (append (string->list (number->string (first d)))
                                                   (string-adapt (rest d))))
                      (else (cons (first d) (string-adapt (rest d)))))))
        (list->string (string-adapt (abbreviate-x (string->list a-string))))))
    ;; Test
    (check-expect (abbreviate "hellooo wooorldd") "hel2o3 wo3rld2"
    

    亲切问候

    这是我对这个问题的看法

    第一个称为prefix的过程将告诉您字符串开头有多少个连续的相同字母。我使用字符串->列表来处理列表,而不是子字符串:

    (define (prefix str)
      (let ((chars (string->list str)))
        (let loop ((chars chars) (c #\0) (l 0))
          (if (empty? chars)
              (values l c)
              (if (= l 0)
                  (loop (cdr chars) (car chars) (add1 l))
                  (if (char=? (car chars) c)
                      (loop (cdr chars) c (add1 l))
                      (values l c)))))))
    
    它将返回2个值:出现次数和相关字符:

    (prefix "")
    0
    #\0
    (prefix "x")
    1
    #\x
    (prefix "hello")          
    1
    #\h
    (prefix "hhhello")     
    3
    #\h
    
    第二个函数rle将使用第一个函数在字符串上循环:

    (define (rle str)
      (let loop ((str str) (res '()))
        (if (= (string-length str) 0)
            (string-join (reverse res) "")
            (let-values (((l c) (prefix str)))
              (loop (substring str l) 
                    (cons 
                     (if (= l 1) 
                         (~a c)
                         (~a c l))
                     res))))))
    
    比如

    (rle "hellooo wooorldd")
    "hel2o3 wo3rld2"
    

    如何查找连续字符?比较列表中的第一个值和第二个值?这是我的主要问题。我似乎想不出一种方法来比较连续的字符。谢谢你的提示。@saurs我添加了一些额外的提示,让你开始学习。谢谢你的提示对我帮助很大!只有一个问题,我不允许使用
    drop
    。有没有其他方法可以获得相同的结果?@saurs您必须手动实现自己版本的
    drop
    ,这是无法逃避的-当找到连续序列时,您必须跳过所有重复的字符(将其视为推进递归的
    cdr
    操作的可变数量)所以我想知道,当你说你的问题是大学水平的时候,你到底想表达什么(因为你也用同样的方式注释了你的最后一个问题)?真的很简单吗?你想欺骗你的作业?还是别的什么?我真的很好奇。我目前正在学习一门大学水平的课程。我不是在寻找直截了当的答案,而是帮助我走上正确的道路。我指出这个问题是大学水平的,因为我得到的答案可能会实现我在课堂上还没有学到的概念。由于我还没有学会这些概念,我不允许在作业中使用它们。我明白了。简单地说你正在做一项作业,并且到目前为止你所学的概念是:在这里列出概念,这可能会更清楚。不同的课程以不同的速度教授不同的概念,所以最好明确说明你能使用什么。