初学者方案:在不使用反向的情况下反转数字列表中的数字

时间:2013-03-19 03:22:34

标签: scheme racket

示例:(反向列表(列表1 2 3 4))=> 4321注意:我不允许使用string-> num或num->字符串或反向。

因此消耗了列表并创建了反向编号(不再是列表)

我遇到了递归逻辑问题。

(define (reverse-list lofd)
 (cond [(empty? lofd) empty]
       [else (+ (* (exp 10 (something that starts at 0 and adds one extra everytime))
                   (first lofd))
                (convert-to-decimal (rest lofd)))]))

我的代码启动并将第一个数字转换为num1 * 10 ^ 0,然后添加递归的数字。

我遇到的问题是如何使它在递归时指数为10 ^ 0然后上升到1,2,3 ......直到列表的长度减去1?我的逻辑/模板也是正确的吗?谢谢!

3 个答案:

答案 0 :(得分:4)

强烈建议:在精神和信件中遵循Design Recipe for list structures。这个问题足够新颖,你不会轻易搞定。您需要Design Recipe步骤所需的额外支持。

在这种特定情况下,你真的需要一套很好的例子(测试用例)来帮助你,因为这个问题的解决方案并不是很明显。这很棘手,因为这个功能不是从列表到列表:它是从列表到数字,所以你必须有一个强大的套件来帮助你发现愚蠢的错误。

例如,该怎么办?

(check-expect (reverse-list empty) <fill-me-in>)

是?我们应该考虑空列表吗?这是一个奇怪的输入吗?这是否合情合理? 合同是否说我们必须处理空列表作为输入,还是可以保证它只接受非空列表?这是您需要预先解决的问题!你现在在代码中所拥有的东西当然不是正确的,因为你的合同类型......好吧,你没有正式表达合同,但是一旦你做了,你就会发现基本情况必须是不同的比你到目前为止写的还要多。

在引用的关于Design Recipe的链接中,第5部分至关重要:一旦掌握了函数模板,就需要了解自然递归计算的内容。使用具体的测试用例来帮助。通过查看代码,您可能已跳过此步骤,因为您编写的代码似乎没有考虑这样的问题:“自然递归计算的是什么?”


具体而言,如果我们这样做:

(reverse-list (list 1 2 3 4))

我们想要答案是什么?你自己说:

(reverse-list (list 1 2 3 4))   ==>   4321

考虑自然递归将是什么:

(reverse-list (list 2 3 4))

这有什么价值?我们知道它一定是

(reverse-list (list 2 3 4))     ==>   432

一旦你搞清楚了,就问问自己:自然递归的价值与原问题的答案有任何关系吗?

鉴于我们正试图解决:

(reverse-list (list 1 2 3 4))   ===>   4321

我们有1(列表的第一部分)和432(来自自然递归),我们可以将1432放在一起某种方式获得4321


重复此操作以获取一些示例。少数人,我的意思是不止一个。 :)为这些例子具体做这件事,你的大脑将更好地拍摄模式匹配和推广,以弄清楚递归案例的代码必须是什么。

也就是说,一旦你有足够的练习来确定如何为具体案例找到正确的答案,那么去看看你是否可以用具体的价值表达你所做的事情,回到程序中的原始术语。例如如果你弄明白:

we want to get 4321 out of 1 and 432:
    => 1 + 10 * 432

...  other examples you worked out...

让我们用前缀表示法重新表达这些:

we want to get 4321 out of 1 and 432:
    => (+ 1 (* 10 432))

...  other examples you worked out...

哪些部分正在发生变化?哪些部分保持不变?第一个变化部分代表什么?第二个变化部分代表什么?那就是:

we want to get 4321 out of 1 and 432:
    => (+ 1 (* 10 432))

...  other examples you worked out ...

we want to get (reverse-list lst) out of (first lst) and (reverse-list (rest lst))
    ==> ???

一旦看到模式,那么你已经找到了需要的代码用于递归案例。但请注意,你真的需要一套例子:试图概括出一个具体的例子是不足以让你的大脑看到模式。你的大脑需要通过计算多个例子来重复,才能开始看到模式。

答案 1 :(得分:1)

除了输入列表之外,您还需要传递另一个参数。如果需要,创建一个新的帮助程序(或内部过程,或名为let等),以使其起作用。这两个参数将跟踪列表中的当前位置,以及当前的指数10.这些内容如下:

(define (reverse-list lofd n)
  (cond [(empty? lofd) ; what do we return if the list is empty?
         <???>]        ; not the empty list! we're building a number
        [else          ; otherwise add this term, taking the
         (<???> <???>  ; current element times current 10^n and
            (reverse-list <???> <???>))])) ; advance recursion over lofd and n

使用以下初始值调用该过程:

(reverse-list (list 1 2 3 4) 0)
=> 4321

答案 2 :(得分:1)

这是一个Scheme解决方案;它使用像null?,car和cdr这样的东西,它们具有历史重要性但不在你的“学习球拍”词汇中。也许它会说明一种方法。

(define (list->reverse-number l)
  (if (null? l)
      0
      (+ (car l) (* 10 (list->reverse-number (cdr l)))))

如果您坚持尝试使用expt,那么您可以尝试这样的事情(使用named-let,这可能超出您的水平):

(define (list->reverse-number l)
  (let reversing ((l l) (n 0))
    (if (null? l)
        0
        (+ (* (expt 10 n) (car l))
           (reversing (cdr l) (+ n 1))))))

但我不知道上述内容是否有效。实际上,这也有效。