简体   繁体   English

在Scheme / lisp中创建n个元素的列表?

[英]Creating a list of n elements in Scheme/lisp?

I am trying to create a list of n elements. 我正在尝试创建n个元素的列表。 It must produce this output: 它必须产生以下输出:

(my-list 5)
 >> 0 1 2 3 4

I have the function below: 我有以下功能:

 (define (my-list n)
    (cond
          ((<= n 0) '())

    (else  (reverse-list   (cons (- n 1) 
                           (my-list(- n 1)))))
    )
 )

and this is producing 这正在产生

(my-list 10)
>>(8 6 4 2 0 1 3 5 7 9)

I understand this is due to reversing the list at every recursive call, but I am not sure what is the correct way. 我知道这是由于在每次递归调用时都会反转列表,但是我不确定什么是正确的方法。 Also my reverse-list is working fine. 我的反向列表也很好。

Thanks in advance! 提前致谢!

A standard idiom in Scheme 'build-and-reverse' suggests you only reverse the list once, at the very end, when its reverse has been completely built (thus reducing the complexity down to O(N) from quadratic.) 方案“构建和反转”中的一个标准习惯用法建议您仅在列表完全反转后才反转一次列表(从而将复杂度从二次降低到O(N))。

So yes, you end up in a tail call to reverse but the list should be built without doing it. 因此,是的,您最终遇到了一个reverse调用,但是列表应该在不执行的情况下构建。 Scheme has plenty of local recursive binding constructs. Scheme具有大量的本地递归绑定构造。

But. 但。

If you build a range starting with the largest value (that should be one greater than the last element to the list) you don't need to reverse it in the end, at each iteration step you decrease a counter and prepend its new value to those already accumulated: 如果您以最大值开始建立范围(该范围应比列表中的最后一个元素大一个),则无需在最后将其取反,在每个迭代步骤中,您减少一个计数器并将其新值添加到那些已经积累的:

(define (range n)
   (let rng ((m (- n 1)) (ret-val '())) ; named-let is very useful for small local recursive closures
      (if (< m 0)                       ; that original (<= n 0) check is also handled here
         ret-val                        ; here, the result is returned; note we don't need to reverse it
         (rng (- m 1) (cons m ret-val))))))

(display (range 10))
(newline)

prints 版画

(0 1 2 3 4 5 6 7 8 9)

Or, to demonstrate the build-and-reverse, we can start with the lowest value: 或者,为了演示构建和反转,我们可以从最低值开始:

(define (range-asc n)
   (let rng ((m 0) (ret-val '()))
      (if (= m n)
         (reverse ret-val) ; since we started from zero, we need to reverse it
         (rng (+ m 1) (cons m ret-val)))))

(Looks like I still remember/can recover some Scheme. :-O) (看起来我仍然记得/可以恢复一些Scheme。:-O)

First of all, your code. 首先,您的代码。 Properly formatted it should look something like: 格式正确的文件应类似于:

(define (my-list n)
    (cond ((<= n 0) '())
          (else (reverse-list (cons (- n 1) 
                                    (my-list (- n 1)))))))

Problem you have, is reverse-list call. 您遇到的问题是reverse-list调用。 It happens every time you add new element to the list. 每当您将新元素添加到列表中时,它就会发生。 You can fix it in many ways, but simple solution is to wrap your recursive code into local function, and do some additional operations (reverse in your case) when it returns. 您可以通过多种方式对其进行修复,但是简单的解决方案是将递归代码包装到本地函数中,并在返回时执行一些其他操作(在您的情况下为反向)。

(define (my-list n)
    (define (build-list m)
        (cond ((<= m 0) '())
              (else (cons (- m 1)
                          (build-list (- m 1))))))
    (reverse-list (build-list n)))

So, inside my-list function, first we define recursive part as a local function build-list . 因此,在my-list函数内部,首先我们将递归部分定义为局部函数build-list This is exactly your code, but with call to reverse-list removed. 这正是您的代码,但是删除了对reverse-list调用。 This part will build your list, but as you know, in reverse order. 这部分将建立您的列表,但您知道的顺序相反。 But that is no longer a problem, since we can reverse it when local function returns. 但这不再是问题,因为我们可以在局部函数返回时将其反转。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM