13

LazySeq に要素が含まれているかどうかを判断する慣用的な方法はありますか? Clojure 1.5 の時点で、呼び出すとcontains?IllegalArgumentException がスローされます。

IllegalArgumentException contains? not supported on type: clojure.lang.LazySeq      
clojure.lang.RT.contains (RT.java:724)

1.5 より前は、私の知る限り、常に false を返していました。

contains?LazySeq の呼び出しは無限になる可能性があるため、返されない可能性があることを知っています。しかし、そうではないことがわかっていて、熱心に評価されても気にしない場合はどうなりますか?

私が思いついたのは次のとおりです。

(defn lazy-contains? [col key]
  (not (empty? (filter #(= key %) col))))

しかし、それはまったく正しくありません。より良い方法はありますか?

4

2 に答える 2

16

まず、レイジー seq はメンバーシップのチェックには効率的ではありません。遅延シーケンスの代わりにセットを使用することを検討してください。

セットが実用的でない場合、ソリューションは悪くありません。考えられるいくつかの改善:

  1. 「空ではない」は少しぎこちないです。ユーザーが if で使用できる nil-or-truthy 値を取得するには、seq を使用するだけで十分です。true または false が必要な場合は、それをブール値でラップできます。

  2. 最初の一致のみを気にするので、filter と seq の代わりに some を使用できます。

  3. 等価述語を記述する便利な方法は、#{key} のようなリテラル セットを使用することですが、key が nil の場合、nil が見つからない場合でも常に nil を返します。

一緒にあなたを与える:

(defn lazy-contains? [col key]
  (some #{key} col))
于 2013-04-28T17:04:08.083 に答える
5

some例の代わりにasを使用するfilterと、シーケンス全体の評価を強制するのではなく、値が見つかるとすぐに戻ります。

(defn lazy-contains? [coll key]
  (boolean (some #(= % key) coll)))

編集:結果をブール値に強制しない場合は、キーが見つからない場合のnil代わりに取得することに注意してください。false

于 2013-04-28T16:33:39.657 に答える