Flattening a map by join the keys

北战南征 提交于 2019-12-30 04:10:08

问题


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".


回答1:


(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}


来源:https://stackoverflow.com/questions/17901933/flattening-a-map-by-join-the-keys

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!