Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Recursion 将具有默认值的键添加到嵌套clojure hashmap_Recursion_Clojure_Hashmap_Clojurescript - Fatal编程技术网

Recursion 将具有默认值的键添加到嵌套clojure hashmap

Recursion 将具有默认值的键添加到嵌套clojure hashmap,recursion,clojure,hashmap,clojurescript,Recursion,Clojure,Hashmap,Clojurescript,我试着做Clojure,但还是坚持使用嵌套的hashmap。 我有一个这样的结构: {:type "view" children: [ {:type "view" :id "123"} {:type "view" :children [ {:type "view"}]}]} {:type "view" :id "43434" children: [ {:type "view" :id "123

我试着做Clojure,但还是坚持使用嵌套的hashmap。 我有一个这样的结构:

{:type "view" 
 children: [
     {:type "view" 
      :id "123"} 
     {:type "view" 
      :children [
         {:type "view"}]}]}
{:type "view" 
 :id "43434"
 children: [
     {:type "view" 
      :id "123"} 
     {:type "view" 
      :id "456"
      :children [
         {:type "view"
          :id "5656"}]}]}
现在我想用随机字符串(如果不存在)将字段
:id
添加到每个hashmap。要得到这样的东西:

{:type "view" 
 children: [
     {:type "view" 
      :id "123"} 
     {:type "view" 
      :children [
         {:type "view"}]}]}
{:type "view" 
 :id "43434"
 children: [
     {:type "view" 
      :id "123"} 
     {:type "view" 
      :id "456"
      :children [
         {:type "view"
          :id "5656"}]}]}

您可以使用
clojure.walk/postwark
执行此操作:

 (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"}]}]}

…其中,
数据
是您的输入映射
postwalk
正在遍历嵌套映射,并且
assoc
在每个没有嵌套映射的映射上使用
:id
键(随机整数字符串)。

您可以使用
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"}]}]}

…其中,
数据
是您的输入映射
postwalk
正在遍历嵌套的映射,并且
assoc
在每个没有嵌套映射的映射上使用
:id
键(一个随机整数字符串)。

除了
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"}

除了
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"}

很好的解决方案,但是请注意,如果输入数据有另一个映射(不仅是
:children
,而且还有例如
:attributes
),它们也会递归地分配ID,因为这个变量不关心数据的语义,而是修改每个映射。尽管如此,如果数据结构不受未来某些更改的影响,也可以。使用
(and(map?v)(nil?(:id v))(=(:type v)“view”)
可能解决了@leetwinski的concernsice解决方案,但请注意,如果输入数据有另一个映射(不仅是
:children
,还包括例如
:attributes
),它们还可以递归地分配ID,因为这种变体不关心数据的语义,而是修改每个映射。尽管如此,如果数据结构不受未来某些更改的影响,也可以。使用
(and(map?v)(nil?(:id v))(=(:type v)“view”)
可能会解决@leetwinski的问题