我有一个函数,它返回值v所在的seq中的索引:
(defn indexes-of [v s]
(map first (filter #(= v (last %)) (zipmap (range) s))))我想要做的是将它扩展到将任意函数应用于存在性测试。我的想法是使用multimethod,但我不确定如何准确地检测函数。我想这么做:
(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))多重方法是这里的路吗?如果是这样的话,我怎样才能完成我想做的事情呢?
发布于 2013-10-25 15:56:53
如果要使用multimethod,则应该使用filter函数,这是根据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不支持一等函数(即lambda),所以没有“函数”数据类型可用于调度,这就是fn?测试的原因。
然而,在这种情况下,noisesmith提出的noisesmith解决方案是正确的选择。
发布于 2013-10-25 15:52:27
(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-25 15:56:09
更简单、更一般的东西怎么样:
(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)https://stackoverflow.com/questions/19594113
复制相似问题