在下面的代碼中,我需要計算鍵盤和驅動器中一個元素的總和的最大值,其總和應小於或等於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