Racket 函数用于查找列表中与谓词匹配的第一个元素

Racket function to find the first element in a list that matches a predicate

在 Linq (.NET) 中,有一个 First() 方法接受一个集合和一个谓词,returns 匹配列表中的第一个元素。例如,以下...

numbers.First(n => n % 2 == 0)

...returns numbers 中的第一个偶数。我想在 Racket 中做同样的事情。

我想到了以下...

(define (first-match f lst)
  (first (filter f lst)))

...但我怀疑这可能非常低效,因为我认为它会在应用 first 之前过滤 整个 列表。 Linq 版本检查每个元素,因此只会遍历列表,直到找到匹配的元素。

任何人都可以证实或反驳我的假设,即我的 first-match 函数将遍历整个列表,如果是,我如何才能生成 Linq 的 First() 方法的更高效版本?

我尝试了以下版本的代码...

(define (first-match f lst)
  (cond [(empty? lst) #f]
        [(f (first lst)) (first lst)]
        [else (first-match f (rest lst))]))

...只会遍历所需的距离,所以应该更有效率,但是 根据一些测试,这并没有快多少,这让我相信第一个版本没有遍历整个列表,或者第二个是。

有人可以发表评论吗? 谢谢

您的假设是正确的,即 (filter f lst) 在将结果传递给 first 之前将遍历整个输入列表(并在此基础上创建一个新列表!)。你的第二个版本效率更高,只会遍历列表直到找到元素。

但是在 Racket 中有一个更简单的解决方案,有一个内置程序可以完全你想要的:看findf

(findf even? '(1 3 5 2 4))
=> 2
(findf even? '(1 3 5 7 9))
=> #f