我会自下而上,为: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”的值是地图的矢量。现在的样子对我来说很好看。 –