我正在努力寻找一种美观,惯用的方式来编写一个函数
(defn remove-smaller
[coll partial-order-fn]
___
)
其中partial-order-fn
接受两个参数并返回-1 0或1,它们是可比较的(分别为更小,相等,更大)或nil
。
remove-smaller
的结果应该是coll,所有小于coll中任何其他项目的项目都会被删除。
示例:如果我们定义了一个部分订单,例如数字正常比较,字母也是如此,但字母和数字不具有可比性:
1 < 2 a < t 2 ? a
然后我们会:
(remove-smaller [1 9 a f 3 4 z])
==> [9 z]
答案 0 :(得分:2)
(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))
这会输出(9 \z)
,这是正确的,除非您希望返回值与coll
的类型相同。
答案 1 :(得分:1)
在实践中我可能只使用汤姆的答案,因为没有算法可以保证比O(n ^ 2)最坏情况的性能更好并且它易于阅读。但是如果性能很重要,那么选择一个始终 n ^ 2的算法并不好,如果你能避免它;下面的解决方案避免重新迭代已知不是最大值的任何项目,因此如果该集合实际上是完全有序的,则可以与O(n)一样好。 (当然,这取决于有序关系的及物性,但因为你称之为隐含的部分顺序)
(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))
答案 2 :(得分:0)
(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]
其余项目的顺序可能与输入集合不同,但是相等的“分区”之间没有顺序