我會自下而上,爲:tags
條目創建轉換函數,然後爲:metrics
,然後爲:sources
。
讓我們說我們的變換函數產生的IDS只是通過計算標籤(僅僅是一個例子,它可以很容易地後來改變):
(defn transform [tags] (count tags))
user> (transform ["asd" "dsf"])
;;=> 2
然後應用轉型的指標項:
(defn transform-metric [{:keys [tags] :as m}]
(assoc m :id (transform tags)))
user> (transform-metric {:tags ["a noether tag" "aegn"]})
;;=> {:tags ["a noether tag" "aegn"], :id 2}
現在使用transform-metric
更新源條目:
(defn transform-source [s]
(update s :metrics #(mapv transform-metric %)))
user> (transform-source {:tags ["s:my:tags"],
:metrics [{:tags ["a tag"]}
{:tags ["a noether tag" "aegn"]}
{:tags ["eare" "rh"]}]})
;;=> {:tags ["s:my:tags"],
;; :metrics [{:tags ["a tag"], :id 1}
;; {:tags ["a noether tag" "aegn"], :id 2}
;; {:tags ["eare" "rh"], :id 2}]}
和最後一步是轉換整個數據:
(defn transform-data [d]
(update d :sources #(mapv transform-source %)))
user> (transform-data data)
;;=> {:tags ["type:something" "gw:somethingelse"],
;; :sources [{:tags ["s:my:tags"],
;; :metrics [{:tags ["a tag"], :id 1}
;; {:tags ["a noether tag" "aegn"], :id 2}
;; {:tags ["eare" "rh"], :id 2}]}]}
所以,我們在這裏完成。
現在請注意transform-data
和transform-source
幾乎是相同的,所以我們可以產生這樣的更新功能的效用函數:
(defn make-vec-updater [field transformer]
(fn [data] (update data field (partial mapv transformer))))
具有這種功能,我們可以這樣定義深變換:
(def transformer
(make-vec-updater
:sources
(make-vec-updater
:metrics
(fn [{:keys [tags] :as m}]
(assoc m :id (transform tags))))))
user> (transformer data)
;;=> {:tags ["type:something" "gw:somethingelse"],
;; :sources [{:tags ["s:my:tags"],
;; :metrics [{:tags ["a tag"], :id 1}
;; {:tags ["a noether tag" "aegn"], :id 2}
;; {:tags ["eare" "rh"], :id 2}]}]}
並基於這種變壓器構造方法,我們可以做出一個很好的函數來更新矢量地圖向量中的值...結構,任意嵌套層次:
(defn update-in-v [data ks f]
((reduce #(make-vec-updater %2 %1) f (reverse ks)) data))
user> (update-in-v data [:sources :metrics]
(fn [{:keys [tags] :as m}]
(assoc m :id (transform tags))))
;;=> {:tags ["type:something" "gw:somethingelse"],
;; :sources [{:tags ["s:my:tags"],
;; :metrics [{:tags ["a tag"], :id 1}
;; {:tags ["a noether tag" "aegn"], :id 2}
;; {:tags ["eare" "rh"], :id 2}]}]}
UPDATE
除了本手冊的做法,有一個夢幻般的LIB叫specter在那裏,這不完全一樣的東西(以及更多),但顯然更具有普遍性和可用:
(require '[com.rpl.specter :as sp])
(sp/transform [:sources sp/ALL :metrics sp/ALL]
(fn [{:keys [tags] :as m}]
(assoc m :id (transform tags)))
data)
;;=> {:tags ["type:something" "gw:somethingelse"],
;; :sources [{:tags ["s:my:tags"],
;; :metrics [{:tags ["a tag"], :id 1}
;; {:tags ["a noether tag" "aegn"], :id 2}
;; {:tags ["eare" "rh"], :id 2}]}]}
在編輯你的問題來平衡括號,我擔心我可能做了錯誤的修復。原始和期望的數據都有一個只有一個元素的「:sources」向量。它是一個矢量,還是應該剝去多餘的開放方括號? – Thumbnail
鍵「:sources」的值是地圖的矢量。現在的樣子對我來說很好看。 –