更新Clojure原子的多个元素

时间:2018-03-21 12:03:55

标签: clojure

我有一个原子:

(def data (atom[ {:orderid 0 :productid 0 :description "A" :amount 2}  {:orderid 1 :productid 1 :description "A" :amount 2}]))

和我的交换功能:

 (defn edit-order [params]
  (filter
        #(and (= (:orderid %) (:orderid params)))
        @data
  (swap! data (fn [old new] (merge old new)) params))

我得到的结果是:

(println (edit-order  {:orderid 0 :description "edited" :amount 3})) 
;=> [{:orderid 0, :productid 0, :description A, :amount 2} {:orderid 1, :productid 1, :description A, :amount 2} {:orderid 0, :description edited, :amount 3}]

我要做的是将新值更新为旧值,而不仅仅是将其添加为新值。我该怎么做?

;=> [{:orderid 0, :productid 0, :description edited, :amount 3} {:orderid 1, :productid 1, :description A, :amount 2}]

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

解决这个问题的方法是:

(def data (atom
           [{:orderid 0 :productid 0 :description "A" :amount 2}
            {:orderid 1 :productid 1 :description "A" :amount 2}]))

(defn edit-order
  [params]
  (swap! data
         (fn [old-orders]
           (mapv (fn [order]
                   (if (= (:orderid order)
                          (:orderid params))
                     (merge order params)
                     order))
                 old-orders))))

(comment
  (edit-order {:orderid 0 :description "edited" :amount 3})
  #_ [{:orderid 0, :productid 0, :description "edited", :amount 3}
      {:orderid 1, :productid 1, :description "A", :amount 2}]
  )

请注意,您不能仅在矢量中改变一个地图。您正在基于旧的向量创建一个全新的向量,因为原子内的整个数据结构(应该)是不可变的。

答案 1 :(得分:0)

另一个选择,如果你正在进行大量的嵌套结构操作,那就是使用https://github.com/nathanmarz/specter,在这种情况下是“转换”操作。

(ns specterplay.core
  (:require [com.rpl.specter :refer :all]))

(def data (atom[ {:orderid 0 :productid 0 :description "A" :amount 2}  {:orderid 1 :productid 1 :description "A" :amount 2}]))

(defn edit-order!
  [params data]
  (swap! data
         (fn [a] (transform [ALL #(= (:orderid params) (:orderid %))] #(merge % params) a))))

(edit-order! {:description "edited" :amount 3} data)

@data
;; [{:orderid 0, :productid 0, :description "edited", :amount 3} {:orderid 1, :productid 1, :description "A", :amount 2}]