Skip to content

Instantly share code, notes, and snippets.

@cap10morgan
Last active April 9, 2018 16:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cap10morgan/bdcac0e5a56ac626d69d539d91dd0e7a to your computer and use it in GitHub Desktop.
Save cap10morgan/bdcac0e5a56ac626d69d539d91dd0e7a to your computer and use it in GitHub Desktop.
Using Clojure transducers with maps
;; Usually when doing a shallow transform on a map in Clojure I reach for `reduce-kv`, but when I have more than one reduce-kv
;; I start thinking I should use transducers instead.
;; So if I start with something like this:
(ns my.ns
(:require [clojure.edn :as edn]))
(defn strip-key-namespaces [m]
(reduce-kv
(fn [a k v]
(assoc a (-> k name keyword) v))
{} m))
(defn read-values [m]
(reduce-kv
(fn [a k v]
(assoc a k (edn/read-string v)))
{} m))
(defn transform-map [m]
(-> m strip-key-namespaces read-values))
;; I can convert it to use transducers like so:
(defn strip-key-namespace [[k v]]
[(-> k name keyword) v])))
(defn read-value [[k v]]
[k (edn/read-string v)])))
(defn transduce-map
([] {})
([m] m)
([m [k v]] (assoc m k v)))
(transduce (comp (map strip-key-namespace) (map read-value))
transduce-map
{:thingy/foo ":echo", :stuff/bar "2", :whee/baz "[\\a \\b \\c]"})
; => {:foo :echo, :bar 2, :baz [\a \b \c]}
;; ...which a colleague pointed out could be simplified even further to this
;; (in place of the `transduce` call and eliminating the need for `transduce-map`):
(into {} (comp (map strip-key-namespace) (map read-value))
{:thingy/foo ":echo", :stuff/bar "2", :whee/baz "[\\a \\b \\c]"})
; also => {:foo :echo, :bar 2, :baz [\a \b \c]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment