61

fnがtrueと評価されるシーケンスの最初の要素を返す関数を探しています。例えば:

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

上記の偽の関数は1(リストの最後の要素)を返す必要があります。Clojureにこのようなものはありますか?

4

6 に答える 6

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

編集:並行性。f:)いいえ。リスト全体には適用されません。の怠惰のため、最初に一致する要素までの要素のみfilter

于 2012-04-17T14:00:50.037 に答える
56

あなたの場合、イディオムは

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

仕組み:#{1}はセットリテラルです。セットは、argがセットに存在する場合はそのargを評価し、存在しない場合はnilを評価する関数でもあります。すべてのセット要素は「真の」値です(ブール値のfalseを除いて、それはセットではまれです)。some結果が真であった最初のコレクションメンバーに対して評価された述部の戻り値を返します。

于 2012-04-17T14:04:57.747 に答える
22

このスレッドで言及されているいくつかの方法(JDK8およびClojure1.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

結果はreduce、clojure1.7のようにその方法が最も効率的な解決策である可能性があることを示しています。

于 2015-09-04T19:14:23.803 に答える
13

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)))

例:

(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

最終的に、パッチは拒否されました。

審査の結果、これを含めたくないと判断しました。線形検索(特にネストされた線形検索)を使用すると、パフォーマンスが低下します。多くの場合、他の種類のデータ構造を使用する方が適切であるため、この機能はこれまで含まれていませんでした。〜AlexMiller2017年5月12日15:34

于 2018-12-09T12:15:59.300 に答える
12

someはその仕事に最適なツールだと思います:

(some #(if (= % 1) %) '(3 4 1))
于 2012-04-17T14:04:53.857 に答える
7

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
于 2015-02-10T02:38:09.700 に答える