List 如何递归地获取列表中的偶数元素

List 如何递归地获取列表中的偶数元素,list,scheme,List,Scheme,我试图创建一个函数,返回列表中的偶数元素 例如: (evens '(a b c d)) (evens '(a b c d e)) 应该回来 (b d) 下面的代码似乎适用于包含奇数和奇数个元素的列表,但是如果我给它一个包含偶数个元素的列表,它是不正确的 例如: (evens '(a b c d)) (evens '(a b c d e)) 会回来的 (b d) 但是: (evens '(a b c d)) 会回来的 (a c) 有什么想法吗 将我的代码更改为: (DEFINE

我试图创建一个函数,返回列表中的偶数元素

例如:

(evens '(a b c d)) 
(evens '(a b c d e))
应该回来

(b d)
下面的代码似乎适用于包含奇数和奇数个元素的列表,但是如果我给它一个包含偶数个元素的列表,它是不正确的

例如:

(evens '(a b c 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))))
    ))

获取一个错误,表示传递给安全车的对象不是一对?

问题是,如果列表中的元素数为偶数,则会匹配
分支,然后开始
cons
与列表中的
匹配。。。因此,在您的示例中,您得到了
a
,依此类推

但是,更重要的是,对于此函数,您不需要使用
length
。。。您不应该这样做:因为
length
在列表长度中需要线性时间,
evens
现在需要二次时间


建议:您的程序应该“记住”在每个递归步骤中它是处于“奇数”还是“偶数”位置。。。您是如何做到这一点的(有几种方法)?

您的代码缺少一些检查,并且有一些不正确的逻辑

(define (evens lis)
(cond
    ((null? lis) '())   
    ((eq? (cdr lis) '()) '()) ;missing condition
    (else (cons (cadr lis) (evens (cddr lis)))))) ; it is cddr not cdr

在过去的几天里,也有人问过同样的问题。这一次我会给出一个直接的回答,直截了当地说:

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

我将用评论过的例子来回答你的问题,希望你能真正学到一些东西,而不仅仅是给你一些有用的代码。事实上,如果您对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
         (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
将此解决方案简化为只有两个分支。

逐步执行代码,错误应该很明显。(在第一次迭代中)您应该添加新代码,而不是替换旧代码。现在这个问题已经不完整了,部分问题已经不相关了。可能是一个相关的、意气相投的问题的重复。强烈推荐!!在Scheme中,您需要
cddr
功能。此问题是否可以标记为重复问题?或者更确切地说,其他问题,因为这一个似乎吸引了更多的注意力和答案?@PauloMadeira我已经将这一个标记为重复,只剩下第一个问题。