Clojure 给定一个偏序集,删除所有较小的项
我正在努力寻找一种漂亮的、惯用的方法来编写函数Clojure 给定一个偏序集,删除所有较小的项,clojure,Clojure,我正在努力寻找一种漂亮的、惯用的方法来编写函数 (defn remove-smaller [coll partial-order-fn] ___ ) 其中,偏序fn接受两个参数并返回-10或1,它们是可比较的(分别较小、相等、较大)或nil remove size的结果应该是coll,所有小于coll中任何其他项的项都将被删除 示例:如果我们定义了一个偏序,例如数字通常是比较的,字母也是比较的,但字母和数字是不可比较的: 1 < 2 a < t 2 ? a 这
(defn remove-smaller
[coll partial-order-fn]
___
)
其中,偏序fn
接受两个参数并返回-10或1,它们是可比较的(分别较小、相等、较大)或nil
remove size
的结果应该是coll,所有小于coll中任何其他项的项都将被删除
示例:如果我们定义了一个偏序,例如数字通常是比较的,字母也是比较的,但字母和数字是不可比较的:
1 < 2 a < t 2 ? a
这将输出(9\z)
,这是正确的,除非您希望返回值的类型与coll
相同
(def data [1 9 \a \f 3 4 \z])
(defn my-fn [x y]
(when (= (type x) (type y))
(compare x y)))
(defn remove-smaller [coll partial-order-fn]
(mapv #(->> % (sort partial-order-fn) last) (vals (group-by type data))))
(remove-smaller data my-fn)
;=> [9 \z]
剩余项的顺序可能与输入集合不同,但相等“分区”之间没有顺序。实际上,我可能只使用tom的答案,因为没有算法可以保证比O(n^2)更好的最坏情况性能,并且易于阅读。但如果性能很重要,选择一个总是n^2的算法是不好的,如果你能避免它;下面的解决方案避免了对任何已知不是maxes的项进行重新迭代,因此,如果集合实际上是完全有序的,那么它可以与O(n)一样好。(当然,这取决于排序关系的及物性,但既然您称之为隐含的偏序)
您能添加一些输入和输出示例吗?“所有比coll中任何其他项都小的项都将被删除。”将是一个包含单个项的集合,即(max coll)当然,我添加了一个示例。实际上,
max
如果项目是部分订购的(而不是完全订购的),则没有任何意义。只是一个建议:调用函数remove mins
而不是remove mins
?当前名称听起来像是要删除小于给定元素的所有条目。我不理解您的输入。你怎么能把一个字母和一个数字进行比较?@tieTYT你不能,这就是偏序集的意义所在!这仅仅是因为您添加了这样一个假设,即按分组很容易/便宜。谢谢,我实际上是在用递归函数尝试这个性能感知版本,但没有做到。谢谢tom,出于性能原因,我接受了@amalloy answer,但您的版本非常清晰可读。我给它一个+1。再次感谢。
(defn partial-compare [x y]
(when (= (type x) (type y))
(compare x y)))
(defn remove-smaller [coll partial-order-fn]
(filter
(fn [x] (every? #(let [p (partial-order-fn x %)]
(or (nil? p) (>= p 0)))
coll))
coll))
(defn -main []
(remove-smaller [1 9 \a \f 3 4 \z] partial-compare))
(def data [1 9 \a \f 3 4 \z])
(defn my-fn [x y]
(when (= (type x) (type y))
(compare x y)))
(defn remove-smaller [coll partial-order-fn]
(mapv #(->> % (sort partial-order-fn) last) (vals (group-by type data))))
(remove-smaller data my-fn)
;=> [9 \z]
(defn remove-smaller [cmp coll]
(reduce (fn [maxes x]
(let [[acc keep-x]
,,(reduce (fn [[acc keep-x] [max diff]]
(cond (neg? diff) [(conj acc max) false]
(pos? diff) [acc keep-x]
:else [(conj acc max) keep-x]))
[[] true], (map #(list % (or (cmp x %) 0))
maxes))]
(if keep-x
(conj acc x)
acc)))
(), coll))