简体   繁体   English

方案:打印出列表的前n个元素

[英]Scheme: Printing out first n elements of list

First off, scheme: return a lst that only contains the first element of the lst did not help much, as the question was never really answered, and I followed the contributor's suggestions to no success. 首先, 计划:返回仅包含lst的第一个元素的lst并没有多大帮助,因为从未真正回答过该问题,因此我遵循了贡献者的建议,但没有成功。 Furthermore, I am approaching this with a do loop, and have almost achieved the solution. 此外,我正在通过do循环来解决这个问题,并且几乎已经实现了解决方案。

I need to make a procedure that will return the first n items in a passed list. 我需要执行一个过程,该过程将返回传递的列表中的前n个项目。 For example, (first-n 4 '(5 8 2 9 4 0 8 7)) should give (5 8 2 9). 例如,(first-n 4'(5 8 2 9 4 0 8 7))应该给出(5 8 2 9)。

Here is my approach, the display is there to make sure that the loop is working, which it is: 这是我的方法,此处显示的内容可确保循环正常运行,即:

(define (front-n n list)
  (do ((i 0 (+ i 1)))
    ((> i (- n 1)))
    (display (list-ref list i))))

How do I go about making that return a list, or output a list? 我该如何使返回列表或输出列表?

Your do-loop, and @Penguino's recursive function, both fail if there are less than n items in the input list. 如果输入列表中的项少于n个,则do循环和@Penguino的递归函数都将失败。 Here is a simple version based on named-let, renamed take which is the normal name for this function: 这是一个基于named-let的简单版本,重命名take是此函数的常规名称:

(define (take n xs)
  (let loop ((n n) (xs xs) (zs (list)))
    (if (or (zero? n) (null? xs))
        (reverse zs)
        (loop (- n 1) (cdr xs)
              (cons (car xs) zs)))))

Or, if you prefer the recursive function version: 或者,如果您喜欢递归函数版本:

(define (take n xs)
  (if (or (zero? n) (null? xs))
      (list)
      (cons (car xs) (take (- n 1) (cdr xs)))))

The named-let version is preferable to the recursive version, because the recursion isn't in tail position, so it builds a large intermediate stack. named-let版本比递归版本更可取,因为递归不在尾部,因此它构建了一个大的中间堆栈。

You said that you wanted a version using do . 您说过想要使用do的版本。 That's harder, because the test that terminates the loop is performed after the action of the loop, and you need to perform the test before the action. 这更难,因为终止循环的测试是在循环操作之后执行的,并且您需要在操作之前执行测试。 You can either test one-ahead, which is awkward, or use this loop that delays the action until after the test has succeeded: 您可以笨拙地进行单次测试,也可以使用以下循环将操作延迟到测试成功之后:

(define (take n xs)
  (let ((zs (list)))
    (do ((n n (- n 1)) (xs xs (cdr xs)))
        ((or (zero? n) (null? xs)) (reverse zs))
      (set! zs (cons (car xs) zs)))))

The set! set! isn't particularly Schemely, but at least it shares with the named-let version the property that it doesn't build an intermediate stack. 并不是特别有计划的,但是至少它与named-let版本共享不构建中间堆栈的属性。

How about 怎么样

(define (front-n n list)
  (cond ((= 0 n) '())
        (else (cons (car list) (front-n (- n 1) (cdr list))))))

with a little pseudo-error-trapping added. 并添加了一些伪错误陷阱。 Testing with: 测试:

(front-n 4 '(5 8 2 9 4 0 8 7))
(front-n 8 '(5 8 2 9 4 0 8 7))

produces the expected output: 产生预期的输出:

'(5 8 2 9)
'(5 8 2 9 4 0 8 7)
>

Note that the error checking may be useful. 请注意,错误检查可能很有用。

Here is a tail recursive version: 这是尾递归版本:

(define (take n a-list)
  (define (iter counter result sublist)
    (cond
      [(empty? sublist) result]
      [(< counter n)
       (iter
         (+ counter 1)
         (append result (list (car sublist)))
         (cdr sublist))]
      [else result]))
  (cond
    [(= n 0) '()]
    [else (iter 0 '() a-list)]))

It differs slightly from the library procedure, because the library procedure throws an error, if you give a take count which is larger than the length of the list, while this function returns the whole list in that case. 它与库过程略有不同,因为如果给出的盘点计数大于列表的长度,则库过程将引发错误,而在这种情况下,此函数将返回整个列表。

Note however, that it makes use of append. 但是请注意,它利用了附加。 I could not figure out a way around that yet. 我还没办法解决。

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

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