2017-06-15 62 views
0

我想知道是否有人可以幫助我找到正確的函數來使用合併與獲得所需的地圖值合併作爲一個單一的載體。彙總地圖值到一個向量

謝謝!

; works great -single vector 
(merge-with vector {:a "b"} {:a "d"} {:a "c"}) 
; {:a ["b" "d"]} 

; uh-oh... now we are beginning to nest each set 
(merge-with vector {:a "b"} {:a "d"} {:a "c"}) 
;{:a [["b" "d"] "c"]} 

; what I want: 
; {:a ["b" "d" "c"]} 
+0

樣子(merge- with(comp flatten vector){:a「b」} {:a「d」} {:a「c」})會這樣做 – zach

回答

0

From this answer我們可以用同樣的原則:

(merge-with (comp #(into [] %) flatten vector) {:a "b"} {:a "d"} {:a "c"}) 
{:a ["b" "d" "c"]} 
1

雖與扁平化的辦法解決您的具體問題,這是不具有普遍性。根據你的問題,我猜你需要一個關鍵字地圖作爲結果向量。它的工作原理是,當所有的地圖都包含完全相同的密鑰時。但你猜以下極端案例:

user> (merge-with (comp flatten vector) {:a "b"}) 
;;=> {:a "b"} oops! you following processing probably wants {:a ["b"]} 

user> (merge-with (comp flatten vector) {:a "b"} {:c "d"}) 
;;=> {:a "b", :c "d"} once again! 

user> (merge-with (comp flatten vector) {:a ["b"]} {:a ["c" ["d"]]}) 
;;=> {:a ("b" "c" "d")} 
;; here i can see some inconsistent behavior, breaking the initial data form: would't you rather want {:a [["b"] ["c" ["d"]]]} ? 

如此,因爲你正在做的事情進行生產,而不是學習, 我會建議使用以下方法:你可以做的函數,合併地圖,而且處理出現在結果中的特殊方式單一(或第一)鍵:

(defn smart-merge-with [first-val-fn merge-fn & args] 
    (when (seq args) 
    (reduce (fn [acc items-map] 
       (reduce (fn [acc [k v]] 
         (if (contains? acc k) 
          (update acc k merge-fn v) 
          (assoc acc k (first-val-fn v)))) 
         acc items-map)) 
      {} args))) 

現在你可以只是包裝的第一個值到一個載體,然後,當有另一個值具有相同的鍵出現只是將其添加到那個矢量:

user> (smart-merge-with vector conj {:a 10 :b 30} {:a 20 :c 30} {:c 1} {:d 100}) 
;;=> {:a [10 20], :b [30], :c [30 1], :d [100]} 

user> (smart-merge-with vector conj {:a [10] :b 30} {:a 20 :c 30} {:c 1} {:d 100}) 
{:a [[10] 20], :b [30], :c [30 1], :d [100]} 

此外,現在你可以更復雜的邏輯添加到地圖融合,例如像一些積累:

user> (smart-merge-with (fn [x] {:items [x] :sum x}) 
         (fn [x y] (-> x 
             (update :items conj y) 
             (update :sum + y))) 
         {:a 10 :b 20} {:b 30 :c 40} {:c 1 :d 2}) 
;;=> {:a {:items [10], :sum 10}, 
;; :b {:items [20 30], :sum 50}, 
;; :c {:items [40 1], :sum 41}, 
;; :d {:items [2], :sum 2}} 
0

或滾動你自己的功能:

(merge-with #(if (vector? %1) (conj %1 %2) (vector %1 %2)) {:a "b"} {:a "d"} {:a "c"})