Initializing elements of a map conditionally in Clojure

You could do something like

(let [not-nils #{:gender}]
  (defn create-record [data]
    (into {} (for [[k v] {:username (data :username)
                          :first-name (get-in data [:user-info :name :first])
                          :last-name (get-in data [:user-info :name :last])
                          :gender (get-in data [:user-info :sex])}
                   :when (not (and (nil? v) (not-nils k)))]
               [k v]))))

I would use a combination of merge and when-let for these optional parameters.

The core idea is to merge in either a single element map or nil for each of the optional parameters. Merging in nil will do nothing, so you won't see the nil in the map.

(defn create-record [data]
  (let [res (merge {:username (data :username)
                    :first-name (get-in data [:user-info :name :first])
                    :last-name (get-in data [:user-info :name :last])}
                   (when-let [gender (get-in data [:user-info :sex])]
                     {:gender gender}))]
    res))

Depending on how frequently you need to do this, I would recommend writing a short macro or function around the when-let to keep the code more concise.


(defn create-record [data]   
   (merge {:username   (data :username)
           :first-name (get-in data [:user-info :name :first])
           :last-name  (get-in data [:user-info :name :last])}
           (when       
             (get-in data [:user-info :sex]) 
             {:gender (get-in data [:user-info :sex])})))

Just add when for each element you want to check if it is not nil and then it will return a map to be merged or nil that will not affect the return map value.

You can merge several maps together so there is no limit of maps to merge and you can return a separate map for each element that is not nil.


(cond-> {:username   (data :username)
         :first-name (get-in data [:user-info :name :first])
         :last-name  (get-in data [:user-info :name :last])}
    (get-in data [:user-info :sex]) (assoc :gender (get-in data [:user-info :sex])))

Tags:

Clojure