首页 > 解决方案 > 使用交换!在嵌套地图上

问题描述

我正在关注 Professional Clojure 一书的第 6 章。

App状态目前定义如下:

(defonce app-state                                          
  (reagent/atom
    {:projects
     {"aaa"
      {:title "Build Whip"
       :stories
       {1 {:title "Design a data model for projects and stories"    
           :status "done"                                           
           :order 1}                                                
        2 {:title "Create a story title entry form"                 
           :order 2}    
        3 {:title "Implement a way to finish stories"
           :order 3}}}}}))                                            

我需要使用swap!添加一个新的键值来表示一个新的故事,由一个具有给定字段值的 id 键控。

(defn add-story! [app-state project-id title status]     ;
  ; Q. How to use swap! to add a key value pair into :stories?
  (swap! app-state update [:projects project-id :stories] assoc      <- INCORRECT CODE HERE
         (unique) {:title title
                   :status status
                   :order (inc (max-order app-state project-id))}))

此处未显示的唯一函数只会生成任何唯一的 uuid。max-order 函数得到了最大的顺序。我不得不修改它,因为本书章节的内容与提供的实际最终代码不一致。这是我的最大订单版本:

(defn max-order [app-state project-id]
  (apply max 0 (map :order (vals (get-in @app-state [:projects project-id :stories])))))

问题:如何使用swap!向其中添加新的键值:stories

我曾经尝试过,但它现在打败了我。

我确实觉得这个嵌套地图不是最好的表示 - 在作为下载提供的最终代码中,作者已更改为更具关系型的模型,项目和故事都作为顶级实体,故事包含 project_id,但是swap!在继续之前解决这个第一次使用会很好。

标签: clojure

解决方案


我认为您可以assoc-in在这种情况下使用它,它比update-in您要实现的目标更简单,更好地描述:

(def app-state
  (atom 
   {:projects
    {"aaa"
     {:title   "Build Whip"
      :stories {1 {:title  "Design a data model for projects and stories"
                   :status "done"
                   :order  1}
                2 {:title "Create a story title entry form"
                   :order 2}
                3 {:title "Implement a way to finish stories"
                   :order 3}}}}}))

(defn unique [] (rand-int 1000000000))

(let [unique-key (unique)]
  (swap! app-state
         assoc-in
         [:projects "aaa" :stories unique-key]
         {:title  (str "Agent " unique-key)
          :status "foxy"
          :order  "some-order-stuff"}))
@app-state
;; => {:projects
;;     {"aaa"
;;      {:title "Build Whip",
;;       :stories
;;       {1 {:title "Design a data model for projects and stories", :status "done", :order 1},
;;        2 {:title "Create a story title entry form", :order 2},
;;        3 {:title "Implement a way to finish stories", :order 3},
;;        295226401 {:title "Agent 295226401", :status "foxy", :order "some-order-stuff"}}}}}


推荐阅读