We're updating the issue view to help you get more done. 

Implement IKVReduce for java.util.map

Description

reduce works on Java maps, but reduce-kv does not:

1 2 3 4 5 6 7 8 9 10 11 12 user=> (def clojure-map {1 2 3 4}) #'user/clojure-map user=> (def java-map (java.util.HashMap. {1 2 3 4})) #'user/java-map user=> (reduce (fn [sum [k v]] (+ sum k v)) 0 java-map) 10 user=> (reduce-kv + 0 clojure-map) 10 user=> (reduce-kv + 0 java-map) IllegalArgumentException No implementation of method: :kv-reduce of protocol: #'clojure.core.protocols/IKVReduce found for class: java.util.HashMap clojure.core/-cache-protocol-fn\ (core_deftype.clj:544)

It's trivial to destructure arguments in a regular reduce, but there are performance implications. The following example yields a 7x speed up when run with the implementation of reduce-kv for java.util.Map as implemented in this patch:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 user=> (def big-clojure-map (into {} (map #(vector % %) (range 10000)))) #'user/big-clojure-map user=> (def big-java-map (java.util.HashMap. big-clojure-map)) Reflection warning, /tmp/form-init7130245387362554027.clj:1:19 - call to java.util.HashMap ctor can't be resolved. #'user/big-java-map user=> (defn reduce-sum [m] (reduce (fn [sum [k v]] (+ sum k v)) 0 m)) #'user/reduce-sum user=> (defn reduce-sum-kv [m] (reduce-kv (fn [sum k v] (+ sum k v)) 0 m)) #'user/reduce-sum-kv user=> (time (dotimes [_ 1000] (reduce-sum big-java-map))) "Elapsed time: 2624.692113 msecs" nil user=> (time (dotimes [_ 1000] (reduce-sum-kv big-java-map))) "Elapsed time: 376.802454 msecs" nil

Environment

None

Status

Assignee

Unassigned

Reporter

import

Labels

Approval

Triaged

Patch

Code

Affects versions

Release 1.8

Priority

Minor