Given a nested map with only keyword keys such as {:foo {:bar 1 :baz [2 3] :qux {:quux 4}} :corge 5}
, how can I implement flatten-map
so that (flatten-map {:foo {:bar 1 :baz [2 3] :qux {:quux 4}} :corge 5} "-")
produces something like {:foo-bar 1 :foo-baz [2 3] :foo-qux-quux 4 :corge 5}
.
My best attempt is:
(defn flatten-map
([form separator] (flatten-map form separator nil))
([form separator prefix]
(if (map? form)
(into {} (map (fn [[k v]]
[(keyword (str prefix (name k)))
(flatten-map v separator (str prefix (name k) separator))])
form))
form)))
As you can see I can't get flatten-map
to select only the "leaves".
(defn flatten-map
([form separator]
(into {} (flatten-map form separator nil)))
([form separator pre]
(mapcat (fn [[k v]]
(let [prefix (if pre (str pre separator (name k)) (name k))]
(if (map? v)
(flatten-map v separator prefix)
[[(keyword prefix) v]])))
form)))
you were unconditionally creating new key / value pairs, even when the value was to be expanded, so I switched map to mapcat so that a result could be "subsumed" into the top level (this also required splitting the (into {} ...)
into the top level version of the form, since we don't actually want any maps anywhere but the top level of the output).
Here is how it works with your example:
user> (flatten-map {:foo {:bar 1 :baz [2 3] :qux {:quux 4}} :corge 5} "-")
{:foo-bar 1, :foo-qux-quux 4, :foo-baz [2 3], :corge 5}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With