我正试图想出一种方法来变换clojure散列图,方法是将另一个映射中的函数应用于每个值。这是我到目前为止所做的:
(defn transform-map [m fm]
(into {} (for [[k v] m]
(let [mfn (get fm k identity)] [k (mfn v)])))
(def m {:a 0 :b 0 :c 0 :d 0})
(def fm {:a inc :b dec :c identity})
(transform-map m fm) ;=> {:a 1, :b -1, :c 0, :d 0}
这样可以正常工作,但只要每个函数都使用一个参数即密钥的当前值即可。如果我想在函数映射中使用一个函数,该函数使用的值不是同一个键中的值,该怎么办?例如,假设我想将密钥:a
和:b
的总和放入密钥:d
中?
我可以尝试类似的事情:
(assoc fm :d (fn[a b] (+ a b)))
但有没有办法可以改变我的transform-map
函数,以便在函数调用中使用适当的参数?
答案 0 :(得分:4)
我建议分解函数以及它们在转换映射中的适用方式。以下是一个示例:
;; functions which take some params and return a result
(defn sub [a b] (- a b))
(defn add [a b] (+ a b))
;; data map
(def data {:a 5 :b 4 :c 3})
;; transformation map key => output key, value is vector of function
;; to apply and the params that function will take from the data map
(def transformations {:a [inc :a]
:b [dec :b]
:c [add :a :b]
:d [sub :b :c]})
; The transformation function
(defn transform-map [m fm]
(into {} (map (fn [[k v]]
[k (apply (first v)
((apply juxt (rest v)) m))])
fm)))
(transform-map data transformations)
答案 1 :(得分:0)
构建它的另一种通用方法是从初始映射开始,然后在其上减少转换函数的集合:
“假设我想把密钥的总和:a和:b放入密钥:d?”
user> (def m {:a 0 :b 0 :c 0 :d 0}
#'user/m
user> (reduce #(%2 %1) m [#(assoc % :a (inc (:a %)))
#(assoc % :b (inc (:b %)))
#(assoc % :d (+ (:a %) (:b %)))])
{:a 1, :c 0, :b 1, :d 2}
虽然这更详细,因为您必须为每个操作指定操作(assoc
)和目标(:b
等),它可以让您表达任何转换并为您提供一个位置提供额外的论据。也许更重要的是,它使得排序明确,而不依赖于地图的内部排序。
您可以将输入结构化为[目标操作]对,使其略显冗长:
user> (reduce (fn [result [target action]]
(assoc result target (action result)))
m
[[:a #(inc (:a %))]
[:b #(inc (:b %))]
[:d #(+ (:a %) (:b %))]])
{:a 1, :c 0, :b 1, :d 2}