Search code examples
clojurehashmaptransformation

Clojure - transform flat map to nested with predecided structure


I'm a newbie to clojure and i'm trying to convert a messages that come in a particular format into another.

ie, i have to convert something like:

   {
     :image-url         ["https://image.png"],
     :topic             "Some title",
     :id                "88ebaf91-a01d-4683-9aa7-629bb3ecea01",
     :short-description "Some Description",
     :mobile-deeplink   "https://deeplink.com/link",
     :partner-name      "partner"}
  

Into something like

{
 :title   "Some title",
 :id      "88ebaf91-a01d-4683-9aa7-629bb3ecea01",
 :content {
           :url         ["https://image.png"],
           :description "Some Description",
           :deeplink    "https://deeplink.com/link",
           :partner     "partner"}}

So in effect, there is a combination of renaming keys and nesting the flat map

What I have done so far was something on the lines of:

(let [message-map {
                   :image-url         :purl
                   :topic             :title
                   :partner-name      :partner
                   :short-description :description
                   :mobile-deeplink   :deeplink}]
  (defn- map-to-body
    [message]
    (-> message
        (clojure.set/rename-keys message-map)
        ;;some sort of (assoc-in) <- this is where i need help in
    )))

Solution

  • Combining assoc-in, a path conversion table, and reduce could be more self-describing and maintainable. You could choose to reduce over either the conversion table or the input message, whichever makes more sense for the data you have.

    (defn transform [m]
      (let [pp '([:image-url [:content :url]]
                 [:topic [:title]]
                 [:id [:id]]
                 [:short-description [:content :description]]
                 ;; etc.
                 )]
        (reduce
         (fn [o [mk ok]]
           (assoc-in o ok (get m mk)))
         {}
         pp)))