在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)))
(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
操作的可变数量)所以我想知道,当你说你的问题是大学水平的时候,你到底想表达什么(因为你也用同样的方式注释了你的最后一个问题)?真的很简单吗?你想欺骗你的作业?还是别的什么?我真的很好奇。我目前正在学习一门大学水平的课程。我不是在寻找直截了当的答案,而是帮助我走上正确的道路。我指出这个问题是大学水平的,因为我得到的答案可能会实现我在课堂上还没有学到的概念。由于我还没有学会这些概念,我不允许在作业中使用它们。我明白了。简单地说你正在做一项作业,并且到目前为止你所学的概念是:在这里列出概念,这可能会更清楚。不同的课程以不同的速度教授不同的概念,所以最好明确说明你能使用什么。