在下面的代码中,我需要计算键盘和驱动器中一个元素的总和的最大值,其总和应小于或等于s
。在Clojure的条件表达式中保存重复计算?
(def s 10)
(def keyboards '(3 1))
(def drives '(5 2 8))
(let [k (sort (fn [x y] (> x y)) keyboards) ; sort into decreasing
d (sort (fn [x y] (> x y)) drives) ; sort into decreasing
]
(loop [k1 (first k) ks (rest k) d1 (first d) ds (rest d)]
(cond
(or (nil? k1) (nil? d1)) -1 ; when one of the list is empty
(< (+ k1 d1) s) (+ k1 d1) ; whether (+ k1 d1) can be saved to compute once?
(and (empty? ks) (empty? ds)) -1
(empty? ks) (if (< (+ k1 (first ds)) s) (+ k1 (first ds)) -1) ; whether (+ k1 (first ds)) can be saved once?
(empty? ds) (if (< (+ d1 (first ks)) s) (+ d1 (first ks)) -1) ; whether (+ d1 (first ks)) can be saved once?
:else (let [bs (take-while #(< % s) [ (+ k1 (first ds)) (+ (first ks) d1) ])]
(if (empty? bs) (recur (first ks) (rest ks) (first ds) (rest ds))
(apply max bs))))))
正如评论所示,我想知道是否有任何方法可以进一步优化条件表达式中的重复添加操作。 在条件检查之前使用let绑定来计算它们可能并不是最优的,因为只有一个条件是真的,因此其他条件的计算将被浪费。
我不知道Clojure编译器是否足够聪明,可以为我优化重复计算,还是有一个巧妙的表达式使得在检查和返回值中只执行一次操作?
任何建议,使代码更习惯性将不胜感激。
也许我误解了,但为什么你担心计算'(+ k1 d1)'所需的时间? –
我只是想学习尽可能最优化。这里重复的操作只是“添加”,成本很低。但是手术可能是任何可能更昂贵的手术。 –
'(sort(fn [xy](> xy))keyboards)'只是'(sort> keyboards)'。 '>'是一个像其他任何函数一样的函数。 – Thumbnail