2013-06-26 23 views
9

aşağıdaki sorununa çözüm bulma konusunda sorun yaşıyorum:Birleştirme iki kompleks veri yapıları

Ben bir harita var Sağlar ki:

(def defaults { 
    :name "John" 
    :surname "Doe" 
    :info {:date-of-birth "01-01-1980" 
      :registered [{:type "newsletter" :name "breaking news" }]} 
}) 

Sonra benzer bir yapısal harita geçmesine ama yapmak istiyorum vektörleri birleştirirsek ve tuşların geri kalanını yaz:

(def new { 
    :name "Peter" 
    :info {:date-of-birth "11-01-1986" 
      :registered [{:type "alert" :name "mobile-alert" }]} 
}) 

ve bu sonucu istiyorum:

{:name "Peter" 
    :surname "Doe" 
    :info {:date-of-birth "11-01-1986" 
      :registered [{:type "newsletter" :name "breaking news" } 
          {:type "alert"  :name "mobile-alert" }]}} 

Şimdi böyle statik sözdizimi kullanarak kolayca yapabilirsiniz:

(reduce conj (get-in defaults [:info :registered]) (get-in new [:info :registered])) 

(Orada muhtemelen daha iyi bir yol ...) Ama aşağıdaki özelliklere sahip dinamik bir fonksiyonun daha umuyordum:

bir anahtarın val sonra,bir vektör ise
  1. anında harita
  2. den
  3. güncel yapısıyla değerlerle herhangi anahtarları bilmeden, her iki haritalardan tüm anahtarları tutun 013.210 sağ haritanın vektörü ile vektör (uygun anahtar tabii varsa) önceden yardım için

Teşekkür :)

cevap

20

merge-with işlevine kesinlikle bakmalısınız. Bu mümkündür:

(defn deep-merge [a b] 
    (merge-with (fn [x y] 
       (cond (map? y) (deep-merge x y) 
         (vector? y) (concat x y) 
         :else y)) 
       a b)) 
+0

+1 “Birleştirme” ile ilgili tamamen unutulmuş. –

+0

Mükemmel çalışır. Birleştirme ile ilgisi olduğunu düşündüm ama bunu çözemedim ... Şerefe! –

0

İşte işlevsellik bu tür bir olası uygulama bu. En azından bir başlangıç ​​noktasıdır, verilerinizin olası yapısına bağlı olarak bazı ek doğrulamaya ihtiyaç duyabilirsiniz (örneğin, geçersiz kılan haritanın değeri bir vektör ise, ancak varsayılan haritadaki değer bir koleksiyon bile değil midir?).

(declare merge-maps) 

(defn merge-map [x [k v]] 
    (cond (vector? v) 
      (assoc x k (vec (reduce conj (x k) v))) 
     (map? v) 
      (assoc x k (merge-maps (x k) v)) 
     :esle 
      (assoc x k v))) 

(defn merge-maps [x y] 
    (reduce merge-map x y)) 

(merge-maps defaults new) 

;= {:info {:date-of-birth "11-01-1986", 
;=   :registered [{:name "breaking news", :type "newsletter"} 
;=      {:name "mobile-alert", :type "alert"}]}, 
;= :name "Peter", 
;= :surname "Doe"}