fnをtrueと評価するシーケンスの最初の要素を返す関数を探しています。例:trueを返す関数を満たすmap/list/sequenceの最初の項目を返します。
(first-map (fn [x] (= x 1)) '(3 4 1))
上記の偽関数は1(リストの最後の要素)を返す必要があります。 Clojureにはこういうものがありますか?
fnをtrueと評価するシーケンスの最初の要素を返す関数を探しています。例:trueを返す関数を満たすmap/list/sequenceの最初の項目を返します。
(first-map (fn [x] (= x 1)) '(3 4 1))
上記の偽関数は1(リストの最後の要素)を返す必要があります。 Clojureにはこういうものがありますか?
user=> (defn find-first
[f coll]
(first (filter f coll)))
#'user/find-first
user=> (find-first #(= % 1) [3 4 1])
1
編集:同時実行。 :)いいえ、それはf
全体のリストに適用されません。 filter
の怠惰のために最初の一致するものまでの要素にのみ。
私はsome
が仕事に最適なツールだと思います:#{1}はリテラル集合である:あなたのケースでは
(some #(if (= % 1) %) '(3 4 1))
、イディオムがどのように動作する
(some #{1} [1 2 3 4])
です。 setはargが集合にあればargを評価し、そうでなければnilにする関数でもあります。どんなセット要素も "真実"値です(もちろん、ブール値の偽を除きますが、それはセットの希少性です)。 some
は、結果が真実であった最初のコレクション・メンバーに対して評価された述部の戻り値を戻します。
使う代わりに、チャンクシーケンスのための「オーバーアプリケーション」f
の対処すべきfilter
のdrop-while
:私はいくつかのベンチマークテストを(JDK 8とのClojure 1.7)このスレッドで述べたいくつかの方法を試みたが、やった
(defn find-first [f coll]
(first (drop-while (complement f) coll)))
;;=> #'user/find-first
(find-first #(= % 1) [3 4 1])
;;=> 1
:
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
方法は、Clojureの1.7のように、最も効率的なソリューションであり得ることを示しています。
非常に興味深い。これらをテストしてくれてありがとう、xando。 [Criterium](https://github.com/hugoduncan/criterium)からの数字がある方が良いと思うのですが、私の推測によれば、シーケンス内のこれまでの項目を検索すると、JVMはコードを最適化する。 – Mars
'(first(filter#(%1) '(3 4 1))'? – 4e6
@ 4e6リストのすべての要素に関数を適用するので、大きなリストでは望ましくない。 – Matthew
地図は怠惰なので、私はそうは思わないと思います。 – Bill