2013-07-27 2 views
9

Учитывая вложенную карту с ключевыми словами, такими как {:foo {:bar 1 :baz [2 3] :qux {:quux 4}} :corge 5}, как я могу реализовать flatten-map, так что (flatten-map {:foo {:bar 1 :baz [2 3] :qux {:quux 4}} :corge 5} "-") производит что-то вроде {:foo-bar 1 :foo-baz [2 3] :foo-qux-quux 4 :corge 5}.Свертывание карты путем объединения ключей

Моя лучшая попытка:

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

Как вы можете видеть, что я не могу получить flatten-map выбрать только «листья».

ответ

11
(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))) 

вы безоговорочно создание новых пар ключ/значение, даже если значение должно было быть расширен, поэтому я перешел карту mapcat таким образом, чтобы результат можно было бы «отнести» на верхний уровень (это также требуемое расщепление (into {} ...) в верхнюю версию формы, так как на самом деле мы не хотим, чтобы какие-либо карты находились где угодно, но верхний уровень вывода).

Вот как он работает с вашим примером:

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} 
+0

Отлично! Спасибо. –

Смежные вопросы