構建地圖和dissoc
荷蘭國際集團要強加條件的鑰匙在基於謂詞(在這裏 - nil?
)可能是最簡單的方法(注意,這個函數只測試明確提到的參數;未提及的參數不會被刪除,不管它們的值是否滿足謂詞):
(defn dissoc-when
"Dissoc those keys from m which are mentioned among ks and whose
values in m satisfy pred."
[pred m & ks]
(apply dissoc m (filter #(pred (m %)) ks)))
在REPL:
user> (dissoc-when nil? {:foo nil :bar true :quux nil} :foo :bar)
{:quux nil, :bar true}
雖然一般來說,如果你希望有很多代表某些特定類型的真實世界實體映射的工作,你可能會想要去的記錄 - 和那麼你可以跳過所有的nil
s在你從輸入地圖中提取數值的階段,因爲當被視爲地圖時,記錄總是包含與其字段對應的鍵。例如。
(defrecord Person [username first-name last-name])
然後你就可以分解出的邏輯圖之間的 「模式轉換」:
(defn translate-map
"Transforms the data map in accordance with the spec in table.
Skips nil-valued entries."
[data table]
(->> table
(keep (fn [[to from]]
(when-let [from-val (get-in data from)]
[to from-val])))
(into {})))
現在你create-record
功能成爲translate-map
和map->Person
組成:
(defn create-person [data]
(map->Person
(translate-map data {:username [:username]
:first-name [:user-info :name :first]
:last-name [:user-info :name :last]
:gender [:user-info :sex]})))
如果您更喜歡使用常規地圖,您可以使用類似下面的內容代替等效輸出:
(defn create-person [data]
(merge (zipmap [:username :first-name :last-name] (repeat nil))
(translate-map data {:username [:username]
:first-name [:user-info :name :first]
:last-name [:user-info :name :last]
:gender [:user-info :sex]})))
在REPL(Clojure的記錄版本1。3):
user> (create-person {:username "jsmith"
:user-info {:name {:first "John" :last "Smith"}}})
#user.Person{:username "jsmith", :first-name "John", :last-name "Smith"}
user> (create-person {:username "jsmith"
:user-info {:name {:first "John" :last "Smith"}
:sex :male}})
#user.Person{:username "jsmith", :first-name "John", :last-name "Smith", :gender :male}
撇開:「gender」!=「sex」 – tom