过滤器是如何实现的?

时间:2012-02-27 01:26:21

标签: filter scheme

使用方案功能需要帮助 返回一个列表,其中包含满足给定谓词的给定列表的所有元素。例如,(filter (lambda (x) (< x 5)) '(3 9 5 8 2 4 7))应返回(3 2 4)

5 个答案:

答案 0 :(得分:6)

filterb - 以防万一已经有一个名为filter的函数。

(define filterb
    (lambda (pred lst)
      (cond ((null? lst) '())
            ((pred (car lst)) (cons (car lst) (filterb pred (cdr lst))))
            (else (filterb pred (cdr lst))))))

虽然我确信它可以看起来更好。

答案 1 :(得分:4)

编写filter过程的简单方法:

(define (my-filter pred lst)
  (cond ((null? lst) null)
        ((pred (first lst))
         (cons (first lst) (my-filter pred (rest lst))))
        (else (my-filter pred (rest lst)))))

请注意,我将过程命名为my-filter,因为已经存在一个名为filter的内置过程,并且覆盖其定义不是一个好主意。

答案 2 :(得分:1)

过滤器的教科书定义是其他海报所展示的(非尾部)递归 - 并且理解那个是很重要的。但是,如果你把它写成库函数,那么弄清楚如何使用尾递归来做这件事很有用,这样你就不会用长列表炸掉堆栈或堆:

(define (filter pred? list)
  (define (filter-aux result current-pair xs)
    (cond ((null? xs)
           result)
          ((pred? (car xs))
           (set-cdr! current-pair
                     (cons (car xs)
                           '()))
           (filter-aux result
                       (cdr current-pair)
                       (cdr xs)))
          (else
           (filter-aux result
                       current-pair
                       (cdr xs)))))
  (let ((init (cons 'throw-me-out '())))
    (filter-aux (cdr init) init list)))

或者,使用let loop语法:

(define (filter pred? xs)
  (let ((result (cons 'throw-me-out '()))
        (xs xs))
    (let loop ((current-pair result))
      (cond ((null? xs)
             (cdr result))
            ((pred? (car xs))
             (set-cdr! current-pair
                       (cons (car xs) '()))
             (loop (cdr current-pair) (cdr xs)))
            (else
             (loop current-pair (cdr xs)))))))

答案 3 :(得分:0)

尝试将filter定义为fold-right的实例:

(define (my-filter op xs)
        (fold-right
           (lambda (next result) ...)
           '()
           xs))

提示:使用ifcons

答案 4 :(得分:0)

对于不需要可变列表的备用尾递归filter,您可以使用以下内容:

(define (my-filter f lst)
  (define (iter lst result)
    (cond
      ((null? lst) (reverse result))
      ((f (car lst)) (iter (cdr lst)
                           (cons (car lst) result)))
      (else (iter (cdr lst)
                  result))))
  (iter lst '()))

反向要求你第二次遍历列表,但是它可以在O(n)时间内实现,并且在不可变列表上有不断的堆栈空间,所以整个时间仍然是O(n)。