首先,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))))
如何返回列表或输出列表?
答案 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。我还想办法解决这个问题。