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

时间:2014-04-15 00:54:36

标签: list scheme

首先,scheme: return a lst that only contains the first element of the lst没有多大帮助,因为这个问题从来没有真正得到解答,而且我遵循了贡献者的建议没有成功。此外,我正在通过do循环来接近这个,并且几乎已经实现了解决方案。

我需要创建一个过程,它将返回传递列表中的前n个项目。例如,(first-n 4'(5 8 2 9 4 0 8 7))应给出(5 8 2 9)。

这是我的方法,显示是为了确保循环正常工作,它是:

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

如何返回列表或输出列表?

3 个答案:

答案 0 :(得分:1)

如果输入列表中的项目少于 n ,则do-loop和@ Penguino的递归函数都会失败。这是一个基于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)))))

或者,如果您更喜欢递归函数版本:

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

named-let版本优于递归版本,因为递归不在尾部位置,因此它构建了一个大的中间堆栈。

你说你想要一个使用do的版本。这更难,因为终止循环的测试是在循环操作之后执行的,并且您需要在操作之前执行测试。你可以先测试一次,这很尴尬,或者使用这个循环延迟动作,直到测试成功为止:

(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)))))

set!并非特别是Schemely,但至少它与named-let版本共享它没有构建中间堆栈的属性。

答案 1 :(得分:0)

怎么样

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

添加了一些伪错误捕获。 测试:

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

产生预期的输出:

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

请注意,错误检查可能很有用。

答案 2 :(得分:0)

这是一个尾递归版本:

(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)]))

它与库过程略有不同,因为如果你给出的计数大于列表的长度,那么库过程会抛出一个错误,而在这种情况下这个函数会返回整个列表。

但请注意,它使用了append。我还想办法解决这个问题。