我尝试做Clojure但坚持使用嵌套的hashmap。 我有这样的结构:
{:type "view"
children: [
{:type "view"
:id "123"}
{:type "view"
:children [
{:type "view"}]}]}
现在我想用随机字符串向每个hashmap添加字段:id
(如果不存在)。得到这样的东西:
{:type "view"
:id "43434"
children: [
{:type "view"
:id "123"}
{:type "view"
:id "456"
:children [
{:type "view"
:id "5656"}]}]}
答案 0 :(得分:8)
您可以使用clojure.walk/postwalk
执行此操作:
(walk/postwalk
(fn [v]
(if (and (map? v) (nil? (:id v)))
(assoc v :id (str (rand-int 9999)))
v))
data)
=>
{:type "view"
:id "3086"
:children [{:type "view"
:id "123"}
{:type "view"
:id "8243"
:children [{:type "view" :id "3222"}]}]}
...其中data
是您的输入地图。 postwalk
遍历您的嵌套地图,assoc
在每张没有地图的地图上添加:id
键(随机整数字符串)。
答案 1 :(得分:0)
除了walk
变体之外还有更多:
最简单的解决方案是递归更新
(defn upd [{:keys [id children] :as data}]
(assoc data
:id (if id
id
(str (rand-int Integer/MAX_VALUE)))
:children (mapv upd children)))
#'user/upd
user> (upd data)
;;=> {:type "view",
;; :children [{:type "view", :id "123", :children []}
;; {:type "view",
;; :children [{:type "view", :id "35223257",
;; :children []}],
;; :id "551012526"}],
;; :id "1899442274"}
你也可以使用clojure的拉链:
(require '[clojure.zip :as z])
(loop [curr (z/zipper map? :children (fn [n ch] (assoc n :children (vec ch))) data)]
(if (z/end? curr)
(z/root curr)
(recur (z/next
(let [node (z/node curr)]
(if (:id node)
curr
(z/replace curr
(assoc node :id
(str "id-" (rand-int Integer/MAX_VALUE))))))))))
;;=> {:type "view",
;; :children [{:type "view", :id "123"}
;; {:type "view",
;; :children [{:type "view", :id "id-92807721"}],
;; :id "id-1357268462"}],
;; :id "id-803083206"}