在下面的代码中,我需要计算键盘中的一个元素和驱动器中的一个元素之和的最大值,但总和应小于或等于s 。
(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编译器是否足够聪明,可以为我优化重复计算,还是有一个巧妙的表达式,使得在检查和返回值中只执行一次操作?
任何建议,使代码更习惯性将不胜感激。
In the following code, I need to compute the maximum of the sum of one element from keyboards and one from drives, subject that the sum should be less or equal to s.
(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))))))As indicated in the comments, I wonder if there is any way to further optimize the repeated add operation in the conditional expressions. It may not be optimal to use let bindings to compute them all before the condition checkings, as only one of the condition would be true, thus the computations for the other conditions would be wasted.
I wonder if Clojure compiler would be smart enough to optimize the repeated computation for me, or there is a clever expression to make the operation to be performed only once in both the checking and return value?
Any suggestion to make the code more idiomatic would be appreciated.
最满意答案
如果您想保留当前代码的结构,可以使用Mark Engelberg的更好的cond库:
(require '[better-cond.core :as b]) (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)] (b/cond (or (nil? k1) (nil? d1)) -1 ; when one of the list is empty :let [x (+ k1 d1)] (< x s) x (and (empty? ks) (empty? ds)) -1 :let [y (+ k1 (first ds))] (empty? ks) (if (< y s) (dec y)) :let [z (+ d1 (first ks))] (empty? ds) (if (< z s) (dec z)) :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))))))If you want to keep the structure of your current code, you can use Mark Engelberg's better-cond library:
(require '[better-cond.core :as b]) (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)] (b/cond (or (nil? k1) (nil? d1)) -1 ; when one of the list is empty :let [x (+ k1 d1)] (< x s) x (and (empty? ks) (empty? ds)) -1 :let [y (+ k1 (first ds))] (empty? ks) (if (< y s) (dec y)) :let [z (+ d1 (first ks))] (empty? ds) (if (< z s) (dec z)) :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))))))更多推荐
发布评论