我正在尝试创建一个函数,它将返回列表中的偶数元素。
例如:
(evens '(a b c d))
应该返回
(b d)
下面的代码似乎适用于包含奇数个元素的列表,但如果我给它一个包含偶数个元素的列表,则它是不正确的。
例如:
(evens '(a b c d e))
将返回
(b d)
可是:
(evens '(a b c d))
将返回
(a c)
有什么想法吗?
将我的代码更改为:
(DEFINE (evens lis)
(cond
((null? lis) '())
(else (cons (cadr lis) (evens (cdr lis))))
))
获取一个错误,说传递给safe-car的对象不是一对?
答案 0 :(得分:0)
问题在于,如果您的列表中包含偶数个元素,则modulo
分支会匹配,您可以使用列表的cons
开始car
...因此,例如,您获得a
,依此类推。
但更重要的是,您不需要使用length
来执行此功能......您不应该:因为length
在列表的长度中占用线性时间,{{ 1}}现在需要二次时间。
建议:你的程序应该“记住”在每个递归步骤中它是否处于“奇数”或“偶数”位置......你怎么能这样做(有几种方法)?
答案 1 :(得分:0)
您的代码缺少检查和一些不正确的逻辑。
(define (evens lis)
(cond
((null? lis) '())
((eq? (cdr lis) '()) '()) ;missing condition
(else (cons (cadr lis) (evens (cddr lis)))))) ; it is cddr not cdr
答案 2 :(得分:0)
过去几天,time和again提出了同样的问题。这次我会给出一个直接答案,直截了当地说明:
(define (evens lst)
(if (or (null? lst) ; if the list is empty
(null? (cdr lst))) ; or the list has a single element
'() ; then return the empty list
(cons (cadr lst) ; otherwise `cons` the second element
(evens (cddr lst))))) ; and recursively advance two elements
以下是如何首先进行错误检查:
(define (find-evens lst)
(if (list? lst)
(evens lst)
(error "USAGE: (find-evens [LIST])")))
答案 3 :(得分:0)
我将用评论的例子回答你的问题,希望你能真正学到一些东西,而不仅仅是给出有效的代码。实际上,假设您不熟悉scheme,那么查看几段代码可能会更具启发性。
您的原始定义如下:
(define (evens lis)
(cond (;; Check: Recursion stop condition
(null? lis)
'())
(;; Wrong: Calling length at each step => O(n^2)
;; Wrong: Assuming even element if list has even number of elements
(= (modulo (length lis) 2) 0)
;; Wrong: Recursing with the rest of the list, you'll get odds
(cons (car lis) (evens (cdr lis))))
(else
;; Wrong: Recursing with the rest of the list with cdr, you'll get odds
(evens (cdr lis)))))
之后,您已编辑了问题,将其更新为以下内容:
(define (evens lis)
(cond (;; Check: Recursion stop condition
(null? lis)
'())
(else
;; Check: Building list with second element
;; Wrong: If lis only has 1 element,
;; (cdr lis) is null and (car (cdr list)) is an error.
(cons (cadr lis)
;; Wrong: Recursing with cdr, you'll get odds
(evens (cdr lis))))))
解决方案是检查列表是否至少包含第二个元素:
(define (evens lis)
(cond (;; Check: Recursion stop condition 1
(null? lis)
'())
(;; Check: Recursion stop condition 2: list of length = 1
(null? (cdr lis))
'())
(else
;; Check: Building list with second element
;; The previous cond clauses have already sorted out
;; that lis and (cdr lis) are not null.
(cons (cadr lis)
;; Check: Recurse "the rest of the rest" of lis with cddr
(evens (cddr lis)))))
练习:使用if
和or
将此解决方案简化为只有2个分支。