Skip to content

Instantly share code, notes, and snippets.

@serioga
Last active May 6, 2022 06:54
Show Gist options
  • Save serioga/a4bae990adbb7b9a4e1bac5d4596566a to your computer and use it in GitHub Desktop.
Save serioga/a4bae990adbb7b9a4e1bac5d4596566a to your computer and use it in GitHub Desktop.
Create map from sequence using transducer
(ns map-entries
(:import (clojure.lang MapEntry)))
(defn map-entries
"Returns transducer collecting map-entries from the sequence of keys/values.
Map key is `(kf k)` or just key if `kf` is nil. Map value is `(vf k v)` or
just value if `vf` is nil. Raises exception in case of odd amount of elements
in the input sequence."
([] (map-entries nil nil))
([kf] (map-entries kf nil))
([kf vf]
(fn [rf]
(let [k! (volatile! nil)]
(fn
([] (rf))
([result] (if-some [k @k!]
(throw (ex-info (str "No value supplied for key: " (pr-str k)) {}))
(rf result)))
([result x]
(if-some [k @k!]
(do
(vreset! k! nil)
(rf result (MapEntry. k (cond->> x vf (vf k)))))
(do
(vreset! k! (cond-> x kf kf))
result))))))))
(defn parse-map
"Converts sequence of keys/values to the map with keywordized keys. The `vfs`
is a map of optional functions to apply to corresponding key value."
[xs vfs]
(->> xs (into {} (map-entries keyword (fn [k v] (let [vf (vfs k)]
(cond-> v vf vf)))))))
(parse-map ["progress" "60" "syncready" "3248" "synctotal" "3248"]
{:progress parse-long, :syncready parse-long})
#_=> {:progress 60, :syncready 3248, :synctotal "3248"}
;Evaluation count : 1484262 in 6 samples of 247377 calls.
; Execution time mean : 489,358779 ns
; Execution time std-deviation : 79,326951 ns
; Execution time lower quantile : 392,268845 ns ( 2,5%)
; Execution time upper quantile : 614,896450 ns (97,5%)
; Overhead used : 8,243735 ns
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment