用foldr写过滤器功能?

时间:2016-02-01 19:48:24

标签: scheme racket fold filterfunction

目前正在尝试编写一个过滤函数,它接受一个过程列表和一个数字列表,删除在数字列表的每个元素上都不返回true的过程。

我所做的是以下内容,目前正在执行单个过程并在列表中运行以创建一个列表,说明每个元素的过程是真还是假。

使用foldr或map(如果需要)(非递归)

 (define (my-filter ps xs)
    (foldr (λ (x y)
             (cons (ps x) y)) '() xs))

如果程序至少有一个#f?

,如何删除该程序

即。 目前

> (my-filter even? '(1 2 3 4))
(#f #t #f #t)
> (my-filter even? (2 4))
(#t #t)

> (my-filter (list even?) '(1 2 3 4))
(list)
> (my-filter (list even?) '(2 4))
(list even?)

2 个答案:

答案 0 :(得分:2)

您可以使用Racket的内置andmap过程来解决此问题,该过程会测试列表中所有元素的条件是否为真 - 如下所示:

(define (my-filter ps xs)
  (foldr (lambda (f acc)
           (if (andmap f xs) ; if `f` is true for all elements in `xs`
               (cons f acc)  ; then add `f` to the accumulated output
               acc))         ; otherwise leave the accumulator alone
         '()                 ; initially the accumulator is an empty list
         ps))                ; iterate over the list of functions

请注意,我们没有"删除"输出列表中的函数,而不是在每一步我们决定是否应该将它们添加到输出列表。

foldr的优点是它保留了与输入列表相同的顺序,如果这不是一个要求,foldl更有效,因为它在内部使用尾递归。无论哪种方式,它都按预期工作:

(my-filter (list even?) '(1 2 3 4))
=> '()

(my-filter (list even?) '(2 4))
=> '(#<procedure:even?>)

答案 1 :(得分:1)

从一些一厢情愿的想法开始。假设我们知道所有xs是否对任何给定的#t都返回f

(define (my-filter fs xs)
  (foldr (λ (f y)
           (if (every? f xs)
               (cons f y)
               y))
         '()
         fs))

现在让我们定义every?

(define (every? f xs)
  (cond [(null? xs) #t]
        [(f (car xs)) (every? f (cdr xs))]
        [else #f]))

让我们查看(list even?)

(my-filter (list even?) '(1 2 3 4)) ; ⇒ '()
(my-filter (list even?) '(2 4))     ; ⇒ '(#<procedure:even?>)

让我们在混音中添加另一个测试

(define (gt3? x) (> x 3))

(my-filter (list even? gt3?) '(2 4)) ; ⇒ '(#<procedure:even?>)
(my-filter (list even? gt3?) '(4 6)) ; ⇒ '(#<procedure:even?> #<procedure:gt3?>)

酷!

如果你想看到&#34;漂亮&#34;过程名称而不是#<procedure:...>内容,您可以将object-name映射到结果数组

(map object-name (my-filter (list even? gt3?) '(4 6))) ; ⇒ '(even? gt3?)
  

即使foldl会给你一个反向输出,我仍然认为在这种情况下使用foldl会更好。我的2美分。