2013-03-25 59 views
2

我想通過向每個值應用來自另一個地圖的函數來轉換clojure hashmap的方法。這是我到目前爲止有:在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功能,所以它會在該函數調用中使用適當的參數?

回答

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

我喜歡這種方法,@Ankur。但是,IMO的一個缺點是,由於你在'fm'上映射''map',所以你不能自動通過'm'中沒有'fm'中鍵的鍵到輸出。這很容易通過在缺失的鍵中「合併」來糾正。謝謝! – stand 2013-03-26 18:18:53

+0

是的,在上面的實現中,'轉換'決定了輸出映射鍵。 – Ankur 2013-03-27 06:25:39

+0

嘿@Ankur,很好的回答!但是難道你不能用(map(partial get m)(rest v))來替換(應用juxt(rest v))m)嗎?或者,由於內置的​​地圖實現也可以調用,所以可以進一步簡化事物 - (map m(rest v))。你使用juxt有什麼特別的原因嗎? – 2013-03-30 04:14:24

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

有趣的@Arthur Ufeldt。是否有某種方法可以減少集合中前兩個匿名函數元素中的冗餘? – stand 2013-03-25 23:51:08

+0

通過使其更加具體化,可以減少冗長,儘管這會使表達動作變得複雜,如「a比b多一個」。 – 2013-03-26 00:10:36