0

値 v が存在する seq s のインデックスを返す関数があります。

(defn indexes-of [v s]
  (map first (filter #(= v (last %)) (zipmap (range) s))))

私がやりたいのは、これを拡張して、存在テストに任意の関数を適用することです。私の考えは、マルチメソッドを使用することですが、関数を検出する方法が正確にはわかりません。私はこれをしたい:

(defmulti indexes-of ???)
(defmethod indexes-of ??? [v s]  ;; v is a function
  (map first (filter v (zipmap (range) s))))
(defmethod indexes-of ??? [v s]  ;; v is not a function
  (indexes-of #(= v %) s))

マルチメソッドはここに行く方法ですか?もしそうなら、どうすれば私がやろうとしていることを達成できますか?

4

3 に答える 3

1

より単純でより一般的なものはどうですか:

(defn index-matches [predicate s]
  (map first (filter (comp predicate second) (map vector (range) s))))

user> (index-matches even? (reverse (range 10)))
(1 3 5 7 9)
user> (index-matches #{3} [0 1 2 3 1 3 44 3 1 3])
(3 5 7 9)

lgrapenthin からの提案のおかげで、この関数は遅延入力にも有効になりました。

user> (take 1 (index-matches #{300000} (range)))
(300000)
于 2013-10-25T15:56:09.320 に答える
1

existence testマルチメソッドを使用する場合は、タイプに応じて変化するフィルター関数を使用する必要があります。

そう

(defmulti filter-test (fn [value element] 
                        (cond 
                         (fn? value) :function
                         :else :value)))

(defmethod filter-test :function
  [value element]
   (apply value [element]))

(defmethod filter-test :value
   [value element]
  (= value element))

(defn indexes-of [v s]
   (map first (filter #(filter-test v (last %)) (zipmap (range) s))))

JVM はすぐに使用できるファーストクラスの関数 (ラムダ) をサポートしていないため、ディスパッチする "関数" データ型がないことを考慮してください。これがfn?テストの理由です。

それでもなお、predicateによって提案された解決策noisesmithは、この状況 IMO での適切な方法です。

于 2013-10-25T15:56:53.397 に答える
1
(defmulti indexes-of (fn [v _]
                       (if (fn? v)
                         :function
                         :value)))
(defmethod indexes-of :function
  [f coll]
  (keep-indexed (fn [i v] (when (f v) i)) coll))

(defmethod indexes-of :value
  [v coll]
  (indexes-of (partial = v) coll))
于 2013-10-25T15:52:27.513 に答える