From acb2b216edc7e2527d4da5c6c8dd8c5907369d41 Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Thu, 15 Nov 2012 19:33:47 -0800 Subject: [PATCH] CLJ-99: Make min-key and max-key evaluate k on each argument at most once Previous versions of these functions evaluated k on most argument twice if there were 3 or more. --- src/clj/clojure/core.clj | 20 ++++++++++++++++++-- test/clojure/test_clojure/other_functions.clj | 9 +++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 985532a..4bc5e26 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -4500,7 +4500,15 @@ ([k x] x) ([k x y] (if (> (k x) (k y)) x y)) ([k x y & more] - (reduce1 #(max-key k %1 %2) (max-key k x y) more))) + (let [kx (k x) ky (k y) + [v kv] (if (> kx ky) [x kx] [y ky])] + (loop [v v kv kv more more] + (if-let [w (first more)] + (let [kw (k w)] + (if (> kw kv) + (recur w kw (next more)) + (recur v kv (next more)))) + v))))) (defn min-key "Returns the x for which (k x), a number, is least." @@ -4509,7 +4517,15 @@ ([k x] x) ([k x y] (if (< (k x) (k y)) x y)) ([k x y & more] - (reduce1 #(min-key k %1 %2) (min-key k x y) more))) + (let [kx (k x) ky (k y) + [v kv] (if (< kx ky) [x kx] [y ky])] + (loop [v v kv kv more more] + (if-let [w (first more)] + (let [kw (k w)] + (if (< kw kv) + (recur w kw (next more)) + (recur v kv (next more)))) + v))))) (defn distinct "Returns a lazy sequence of the elements of coll with duplicates removed" diff --git a/test/clojure/test_clojure/other_functions.clj b/test/clojure/test_clojure/other_functions.clj index c23e599..688224b 100644 --- a/test/clojure/test_clojure/other_functions.clj +++ b/test/clojure/test_clojure/other_functions.clj @@ -328,6 +328,15 @@ (apply (apply some-fn (repeat i (comp not boolean))) (range i)))) true)))) + +(deftest test-max-min-key + (are [k coll min-item max-item] (and (= min-item (apply min-key k coll)) + (= max-item (apply max-key k coll))) + count ["longest" "a" "xy" "foo" "bar"] "a" "longest" + - [5 10 15 20 25] 25 5 + #(if (neg? %) (- %) %) [-2 -1 0 1 2 3 4] 0 4)) + + ; Printing ; pr prn print println newline ; pr-str prn-str print-str println-str [with-out-str (vars.clj)] -- 1.8.0