Hi Mark,
Here is a version runs about 1.3x faster on my setup.
(defn flatten-keys [thing]
(letfn [(-map-key [prefix k] (str prefix . (name k)))
(-seq-key [prefix i] (str prefix [ i ]))
(-flatten-entry [make-key prefix result entry]
(let [[k v] entry]
You've probably gotten nearly all of the performance you're going to get
out of it without resorting to mutability, perhaps by threading a
StringBuilder instance through the whole affair, or at least accumulating
not a string (via a sequence of str calls) but a coll and doing a big
apply str
I want to flatten a map of nested maps/vecs
Currently I'm using the fn's:
(defn- flatten-keys* [a ks m]
(cond
(map? m) (reduce into
(map (fn [[k v]]
(flatten-keys* a (if-not (empty? ks)
(str ks
A slightly cleaner version:
(defn- flatten-keys* [a ks m]
(cond
;; Is a map?
(map? m) (reduce into
(map (fn [[k v]]
(flatten-keys* a (str ks . (name k)) v))
(seq m)))
;; Is an arr/vec/seq?
(and
i wasn't able to squeeze that much more out of it, informally maybe around
10% as it gets larger.
(defn- flx
([obj] (flx obj [$] {}))
([obj curr res]
(cond
(map? obj)
(reduce
#(flx (%2 obj) (conj curr (str . (name %2))) %1)
res
(keys obj))
This is probably easier if you do it in two passes: one to assemble the
get-in path down to a value, and another to stringify that path.
(def input {:name {:first Rich :last Hickey} :number [1 415 123 4567]})
;= #'user/input
(def expected {$.number[0] 1, $.number[1] 415, $.number[2] 123,