如何在Clojure中将max应用于具有预定义顺序的值列表?

时间:2012-12-05 20:03:37

标签: clojure

我需要将max运算符应用于以下列表

[Tier20 Tier10 Tier30]

它应该给我

Tier30

预定义的有序列表(从低到高)是

[Tier5 Tier10 Tier20 Tier30 Tier40 Tier50]

在Clojure中实现这一目标的最佳方法是什么?

4 个答案:

答案 0 :(得分:6)

首先定义排序:

user> (def order '[Tier5 Tier10 Tier20 Tier30 Tier40 Tier50])
#'user/order

然后我们将订单映射到可以通过创建map

进行排序的内容
user> (def order-map (zipmap order (range)))
{Tier50 5, Tier40 4, Tier30 3, Tier20 2, Tier10 1, Tier5 0}

如果您需要的是最大/最小值,请使用order-map减少输入

user> (reduce #(if (< (order-map %1) (order-map %2)) %1 %2) 
              '[Tier20 Tier10 Tier30])
Tier30

<小时/> 或者如果你需要完整的排序,那么使用sort-by函数,就像常规排序函数一样,除了它让你有机会在比较之前翻译输入:

user> (sort-by (zipmap order (range)) '[Tier20 Tier10 Tier30])
(Tier10 Tier20 Tier30)

如果您需要经常修改此地图而不是每次都重新排序,那么使用sorted-set-by数据结构来存储您的输入。

答案 1 :(得分:2)

使用reduce。例如,要查找列表L的最大值,您可以执行以下操作:

(reduce max L)

这里真正的问题是你的Tiers是字符串还是更复杂的对象,因为你的帖子并不完全清楚。无论哪种方式,你可以用lambda表达式替换max来拉出字符串的数字部分,如下所示:

(reduce (fn [x y] ...) L)

where ...将是从数据中提取数字部分的表达式。

答案 2 :(得分:1)

这是我刚试过的。杠杆的主要观点是.indexOf上的实例方法clojure.lang.Vector

user> (def x ['Tier5 'Tier10 'Tier20 'Tier30 'Tier40 'Tier50])
#'user/x
user> (index-of x 'Tier10)
; Evaluation aborted.
user> (.indexOf x 'Tier10)
1
user> (def y ['Tier20 'Tier10 'Tier30])
#'user/y
user> (reduce #(max %1 (.indexOf x %2)) y)
; Evaluation aborted.
user> (x (reduce #(max %1 (.indexOf x %2)) 0 y))
Tier30
user>

当然,这是O(n 2 )。如果您将大规模地执行此操作,您可以通过从TierN到其排序索引的哈希映射更好地服务。

答案 3 :(得分:0)

如果数组是java.lang.String,那么可以使用一些互操作:

user=> (def array ["Tier5" "Tier10" "Tier20" "Tier30" "Tier40" "Tier50"])
#'user/array
user=> (defn find-max [m] (reduce #(if (> (.compareTo %1 %2) -1) %1 %2) m))
#'user/find-max
user=> (find-max array)
"Tier50"
user=> (find-max "a")
\a

如果不只是让他们实施Comparable,或创建Comparator