【问题标题】:Add key with default value to nested clojure hashmap将具有默认值的键添加到嵌套的 clojure hashmap
【发布时间】:2018-01-11 22:33:44
【问题描述】:

我尝试使用 Clojure,但坚持使用嵌套的 hashmap。 我有这样的结构:

{:type "view" 
 children: [
     {:type "view" 
      :id "123"} 
     {:type "view" 
      :children [
         {:type "view"}]}]}

现在我想将字段:id 添加到每个带有随机字符串的哈希图(如果不存在)。要得到这样的东西:

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

【问题讨论】:

    标签: recursion clojure hashmap clojurescript


    【解决方案1】:

    您可以使用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 键(一个随机整数字符串)。

    【讨论】:

    • 不错的解决方案,但请注意,如果输入数据有另一个映射(不仅仅是:children,还有例如:attributes),它们也会递归分配ID,因为这个变体没有不关心数据的语义,而是修改每个映射。不过,如果数据结构不受未来变化的影响,那也没关系。
    • 使用(and (map? v) (nil? (:id v)) (= (:type v) "view")) 可能会解决@leetwinski 的顾虑
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-08
      • 2013-05-27
      • 1970-01-01
      相关资源
      最近更新 更多