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))