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
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]" 1
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))
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 (sequent
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