使用 foldr 编写过滤功能?
writing filter function using foldr?
目前正在尝试编写一个过滤函数,该函数接受一个过程列表和一个数字列表,删除在数字列表的每个元素上都不 return 正确的过程。
我所做的是以下内容,目前采用单个过程并遍历列表以创建一个列表,说明每个元素的过程是真还是假。
如果需要,使用 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?)
从一些一厢情愿的想法开始。假设我们知道是否所有 xs
return #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?>)
太棒了!
如果您想查看 "pretty" 过程名称而不是 #<procedure:...>
内容,您可以将 object-name
映射到结果数组
(map object-name (my-filter (list even? gt3?) '(4 6))) ; ⇒ '(even? gt3?)
Even though foldl
will give you a reversed output, I still think it would be better to use foldl
in this case. Just my 2 cents.
您可以使用 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
请注意,我们不"delete"输出列表中的函数,而是在每一步决定是否将它们添加到输出列表中。
foldr
is that it preserves the same order as the input list, if that's not a requirement, foldl
的优点是效率更高,因为它内部使用了尾递归。无论哪种方式,它都按预期工作:
(my-filter (list even?) '(1 2 3 4))
=> '()
(my-filter (list even?) '(2 4))
=> '(#<procedure:even?>)
目前正在尝试编写一个过滤函数,该函数接受一个过程列表和一个数字列表,删除在数字列表的每个元素上都不 return 正确的过程。
我所做的是以下内容,目前采用单个过程并遍历列表以创建一个列表,说明每个元素的过程是真还是假。
如果需要,使用 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?)
从一些一厢情愿的想法开始。假设我们知道是否所有 xs
return #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?>)
太棒了!
如果您想查看 "pretty" 过程名称而不是 #<procedure:...>
内容,您可以将 object-name
映射到结果数组
(map object-name (my-filter (list even? gt3?) '(4 6))) ; ⇒ '(even? gt3?)
Even though
foldl
will give you a reversed output, I still think it would be better to usefoldl
in this case. Just my 2 cents.
您可以使用 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
请注意,我们不"delete"输出列表中的函数,而是在每一步决定是否将它们添加到输出列表中。
foldr
is that it preserves the same order as the input list, if that's not a requirement, foldl
的优点是效率更高,因为它内部使用了尾递归。无论哪种方式,它都按预期工作:
(my-filter (list even?) '(1 2 3 4))
=> '()
(my-filter (list even?) '(2 4))
=> '(#<procedure:even?>)