过滤除数字以外的任何值

Filter out any value other than a number

我正在尝试想出一个程序来过滤除数字以外的任何值。例如:

'(1 2 (a) 3) => '(1 2 () 3)'(1 2 (a 10 11 (b 2 (c))) 3) => '(1 2 (10 11 (2 ())) 3)

这是我目前所拥有的,但它并没有真正起作用,因为它用空列表代替了非数字:

(define (filter-numbers lst)
  (if (null? lst)
      '()
      (if (list? lst)
          (cons
           (filter-numbers (car lst))
           (filter-numbers (cdr lst)))
          (if (number? lst)
              lst
              '())))
  )

程序输出如下:

> (filter-numbers '(1 2 (a) 3))
'(1 2 (()) 3)

而不是:'(1 2 () 3)

您需要先检查子列表中的元素是否为数字 ,然后再 决定是否将其 cons 输出。我认为如果我们稍微重构一下代码会更容易;还有一些提示:不要使用 list?,更喜欢 pair?,因为它更快(与 list? 不同,它不必遍历整个列表)。并且更喜欢 cond 而不是嵌套 if,您的代码将更易于阅读。这就是我的意思:

(define (filter-numbers lst)
  (cond ((null? lst) lst)
        ((not (pair? (car lst)))
         ; check the element while still in a list, if we wait
         ; until we reach an atom it's too late to filter it out
         (if (number? (car lst))
             ; either add the element to the output or skip it
             (cons (car lst) (filter-numbers (cdr lst)))
             (filter-numbers (cdr lst))))
        (else (cons
               (filter-numbers (car lst))
               (filter-numbers (cdr lst))))))

它按预期工作:

(filter-numbers '(1 2 (a) 3))
=> (1 2 () 3)
(filter-numbers '(1 2 (a 10 11 (b 2 (c))) 3))
=> '(1 2 (10 11 (2 ())) 3)