我正在寻找一个函数,它返回序列中的第一个元素,其中fn的计算结果为true.例如:
(first-map (fn [x] (= x 1)) '(3 4 1))
Run Code Online (Sandbox Code Playgroud)
上面的假函数应该返回1(列表中的最后一个元素).在Clojure中有类似的东西吗?
kot*_*rak 62
user=> (defn find-first
[f coll]
(first (filter f coll)))
#'user/find-first
user=> (find-first #(= % 1) [3 4 1])
1
Run Code Online (Sandbox Code Playgroud)
编辑:并发.:)不.它不适f用于整个列表.由于懒惰,仅限于第一个匹配的元素filter.
Mar*_*nik 49
在你的情况下,成语是
(some #{1} [1 2 3 4])
Run Code Online (Sandbox Code Playgroud)
工作原理:#{1}是一个集合文字.如果arg存在于集合中,则set也是评估其arg的函数,否则为nil.任何set元素都是一个"truthy"值(好吧,除了布尔值false,但这在集合中很少见).some返回对结果为真的第一个集合成员计算的谓词的返回值.
象嘉道*_*象嘉道 14
我尝试了这个线程中提到的几个方法(JDK 8和Clojure 1.7),并做了一些基准测试:
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
Run Code Online (Sandbox Code Playgroud)
结果表明,这种reduce方式可能是最有效的解决方案,如clojure 1.7.
vem*_*emv 12
我认为这some是工作的最佳工具:
(some #(if (= % 1) %) '(3 4 1))
Run Code Online (Sandbox Code Playgroud)
Cas*_*sey 12
2016 年有一个补丁提交给 clojure 核心(first (filter pred coll)),它为习语添加了一个有效的快捷方式,它被称为seek.
该实现避免了(first (filter))和(some #(when (pred)))替代方案中的问题。也就是说,它可以有效地处理分块序列,并且可以很好地处理nil?和false?谓词。
修补:
(defn seek
"Returns first item from coll for which (pred item) returns true.
Returns nil if no such item is present, or the not-found value if supplied."
{:added "1.9" ; note, this was never accepted into clojure core
:static true}
([pred coll] (seek pred coll nil))
([pred coll not-found]
(reduce (fn [_ x]
(if (pred x)
(reduced x)
not-found))
not-found coll)))
Run Code Online (Sandbox Code Playgroud)
例子:
(seek odd? (range)) => 1
(seek pos? [-1 1]) => 1
(seek pos? [-1 -2] ::not-found) => ::not-found
(seek nil? [1 2 nil 3] ::not-found) => nil
Run Code Online (Sandbox Code Playgroud)
最终补丁被拒绝了:
经过审查,我们决定不希望包含此内容。使用线性搜索(尤其是嵌套线性搜索)会导致性能不佳 - 通常最好使用其他类型的数据结构,这就是过去未包含此功能的原因。~亚历克斯·米勒 17 年 5 月 12 日下午 3:34
使用drop-while代替filter应该解决f分块序列的“过度应用” :
(defn find-first [f coll]
(first (drop-while (complement f) coll)))
;;=> #'user/find-first
(find-first #(= % 1) [3 4 1])
;;=> 1
Run Code Online (Sandbox Code Playgroud)