返回满足函数返回true的地图/列表/序列中的第一项

我正在寻找一个函数,返回一个序列中的第一个元素,将fn评估为true。 例如:

(first-map (fn [x] (= x 1)) '(3 4 1)) 

上面的假function应该返回1(列表中的最后一个元素)。 在Clojure中有这样的东西吗?

 user=> (defn find-first [f coll] (first (filter f coll))) #'user/find-first user=> (find-first #(= % 1) [3 4 1]) 1 

编辑:并发。 :)不,它不适用于整个名单。 由于filter懒惰,只能到达第一个匹配的元素。

就你而言,这个成语是

 (some #{1} [1 2 3 4]) 

工作原理:#{1}是一组字面值。 一个集合也是一个函数,如果arg存在于集合中则评估其arg,否则为零。 任何set元素都是一个“真值”(好吧,除了布尔值假,但这是一个罕见的集合)。 some返回谓词的返回值,这个谓词是针对第一个集合成员评估的,结果是真实的。

我尝试了这个线程中提到的几个方法(JDK 8和Clojure 1.7),并做了一些基准testing:

 repl> (defn find-first [f coll] (first (filter f coll))) #'cenx.parker.strategies.vzw.repl/find-first repl> (time (find-first #(= % 50000000) (range))) "Elapsed time: 5799.41122 msecs" 50000000 repl> (time (some #{50000000} (range))) "Elapsed time: 4386.256124 msecs" 50000000 repl> (time (reduce #(when (= %2 50000000) (reduced %2)) nil (range))) "Elapsed time: 993.267553 msecs" 50000000 

结果表明, reduce方式可能是最有效的解决scheme,如clojure 1.7。

我认为some是这个工作最好的工具:

 (some #(if (= % 1) %) '(3 4 1)) 

使用drop-while代替filter应该解决分块序列的f “over-application”问题:

 (defn find-first [f coll] (first (drop-while (complement f) coll))) ;;=> #'user/find-first (find-first #(= % 1) [3 4 1]) ;;=> 1