【问题标题】:How to create a function that makes a list that contains 1,2,3,4,5... to n in Scheme如何在Scheme中创建一个包含1,2,3,4,5...到n的列表的函数
【发布时间】:2018-05-24 01:48:30
【问题描述】:

我正在尝试学习 Scheme,但遇到了问题。 我可以创建一个递归函数来创建一个像 (5,4,3,2,1) 这样的列表。但我不知道如何创建一个函数 (比如说(define (make_list n))) 具有升序排列的元素,例如 (1,2,3,4,5....n)。 有人暗示吗?

 (define (make_list n)
  (if (= n 1)
      (list 1)
  (append (list n) (make_list (- n 1)))))

这就是我用 n 元素制作一个列表的方法,它会返回

> (make_list 3)
'(3 2 1)
> (make_list 5)
'(5 4 3 2 1)

我需要的是返回类似的东西:

> (make_list 3)
'(1 2 3)
> (make_list 5)
'(1 2 3 4 5)

【问题讨论】:

  • 我猜你应该从头开始编写解决方案,但惯用的解决方案是:(build-list n add1)

标签: scheme racket


【解决方案1】:

您应该避免在不必要的地方使用 append。 Append 将元素添加到列表的后面,为此它首先需要遍历整个列表才能找到末尾。 Cons 不需要这样做,它可以立即在前面添加元素。

升序和降序都可以使用 cons 创建。

(define (desc-list n)
   (if (= n 1)
      (list 1)
      (cons n (desc-list (- n 1)))))

> (desc-list 5)
'(5 4 3 2 1)

(define (asc-list from to)
   (if (> from to)
      '()
      (cons from (asc-list (+ from 1) to))))

> (asc-list 1 5)
'(1 2 3 4 5)

虽然你也可以使用 append 如果你真的想要。 你所要做的就是反转你传递给附加的参数。

(define (make_list n)
   (if (= n 1)
      (list 1)
      (append (make_list (- n 1)) (list n))))

> (make_list 5)
'(1 2 3 4 5)

所以你很亲密。

【讨论】:

  • 是的,非常接近!我之前尝试过append (make_list (- n 1)) (list n)),但似乎我弄乱了括号。
【解决方案2】:

根据你目前的定义

(make-list 5) = (append (list 5) (make-list 4))
              = { 5 } + { 4 ..... 1 }

但你想要

(make-list 5) = { 1 ..... 4 } + { 5 }
              = (append  ...  ...)

所以要更改结果的顺序,您只需更改 创建结果的顺序。

【讨论】:

    【解决方案3】:

    考虑使用子程序。您可以使用您的代码作为子程序,而在主程序中只使用reverse 的结果:

    (define (make-list n)
      (define (sub n)
        (if (= n 1)
            (list 1)
            (append (list n) (sub (- n 1)))))
      (reverse (sub n)))
    

    另外,更有效的是,您可以使用累加器(在此示例中称为 res);它使用cons 而不是append,并且不需要额外的reverse 步骤:

    (define (make-list n)
      (define (sub n res)
        (if (< n 1)
            res
            (sub (- n 1) (cons n res))))
      (sub n null))
    

    【讨论】:

      【解决方案4】:

      不要使用append 一次列出一个元素。 append 附加两个列表线性时间,因此如果您对参数中的每个元素执行此操作,您可能会使其成为二次时间。

      列表从头到尾都是cons-ed。如果要列出 0..n 列表,则需要在累积时从 n 开始向下计数,如下所示:

      (define (make-list n)
        (define (helper n acc)
          (if (< n 0)
              acc
              (helper (- n 1) (cons n acc))))
        (helper n '()))
      

      有时你不能这样做,然后你通常会先把列表倒过来,然后再倒过来。这是两个线性时间运算,使得最终结果也是线性的:

      (define (sum lst1 lst2)
        (let helper ((lst1 lst1) (lst2 lst2) (acc '()))
          (if (null? lst1)
              (reverse acc)
              (helper (cdr lst1) 
                      (cdr lst2)
                      (cons (+ (car lst1) (car lst2)) acc)))))
      

      【讨论】:

        【解决方案5】:

        只需将 srfi-1 包含 iota function 添加到此线程即可

        ; (iota numElems [start] [step])
        
        > (iota 10)
        (0 1 2 3 4 5 6 7 8 9)
        > (iota 10 0 2)
        (0 2 4 6 8 10 12 14 16 18)
        > (iota 10 10 1)
        (10 11 12 13 14 15 16 17 18 19)
        

        【讨论】:

          【解决方案6】:

          您可以使用range 函数制作升序元素列表:

          > (range 1 20)
          '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
          

          如果您想遍历此列表,请考虑改用in-range,它将根据需要生成列表项,例如:

          > (in-range 1 20)
          #<stream>
          > (for ([i (in-range 1 20)])
                 (displayln (* i 10)))
          10
          20
          30
          ...
          

          但通常mapfilterfold 之类的方法是处理迭代的更好方法。

          在此处阅读文档: https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Flist..rkt%29._range%29%29

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-07-09
            • 2022-01-09
            • 1970-01-01
            • 1970-01-01
            • 2021-05-07
            相关资源
            最近更新 更多