如何更新 Clojure 地图嵌套向量中的试剂原子过滤
How to update a reagent atom filtering in a nested vector of maps in Clojure
假设我有一个试剂原子,其映射向量如下:
(def my-atom (reagent/atom {:id 256
:name "some name"
:lines [{:code "ab43" :name "first nested name" :quantity 4}
{:code "bc22" :name "second nested name" :quantity 1}
{:code "lu32" :name "third nested name" :quantity 1}}] }))
如何更新键的值:某个向量嵌套索引处的数量,例如:将代码为“bc22”的行更新为 10 个数量。
这需要过滤以获取向量的索引,但没有索引,因为按“代码”过滤:
(swap! my-atom assoc-in [:lines 1 :quantity] 10)
我可以用过滤器找到,但我不能交换!数量:
(->> (:lines @my-atom)
(filter #(= (:code %) "bc22")
first))
(require
'[com.rpl.specter :as s])
(let [*a (atom {:id 256
:name "some name"
:lines [{:code "ab43" :name "first nested name" :quantity 4}
{:code "bc22" :name "second nested name" :quantity 1}
{:code "lu32" :name "third nested name" :quantity 1}]})]
(s/setval [s/ATOM :lines s/ALL #(-> % :code (= "bc22")) :quantity] 10 *a))
您可以坚持使用 assoc-in
,但要这样做,您必须以某种方式从 :lines
字段的向量中检索与给定代码关联的索引。
例如,我要一个辅助函数:
(defn code->index [data code]
(->> data
:lines
(map-indexed (fn [i v] [i v]))
(filter (fn [[_ v]] (= (:code v) code)))
ffirst))
;; (code->index @my-atom "bc22")
;; => 1
然后在交换中使用它:
(swap! my-atom assoc-in [:lines (code->index @my-atom "bc22") :quantity] 10)
这里有选项。您可以查找项目的索引,可以映射列表,只更新您感兴趣的项目。
根据具体情况,您还可以考虑在呈现组件时存储元素的索引,或者构建一组 cursors 传递给您的组件。在那种情况下,您只需像更新原子一样更新游标,它会有效地处理更新支持原子。
就我个人而言,我看了这个并想知道您是否首先使用了正确的数据结构。 code
似乎很可能是这里的自然键,尤其是当您希望基于它更新一行时。也许以 code
为键、以整行为值的映射更有意义。这也使得某些不良情况不可能发生(e.x。多行具有相同的code
)。当然,您会丢失订单(除非您以某种方式 re-established 它),这可能是也可能不是问题。
假设我有一个试剂原子,其映射向量如下:
(def my-atom (reagent/atom {:id 256
:name "some name"
:lines [{:code "ab43" :name "first nested name" :quantity 4}
{:code "bc22" :name "second nested name" :quantity 1}
{:code "lu32" :name "third nested name" :quantity 1}}] }))
如何更新键的值:某个向量嵌套索引处的数量,例如:将代码为“bc22”的行更新为 10 个数量。
这需要过滤以获取向量的索引,但没有索引,因为按“代码”过滤:
(swap! my-atom assoc-in [:lines 1 :quantity] 10)
我可以用过滤器找到,但我不能交换!数量:
(->> (:lines @my-atom)
(filter #(= (:code %) "bc22")
first))
(require
'[com.rpl.specter :as s])
(let [*a (atom {:id 256
:name "some name"
:lines [{:code "ab43" :name "first nested name" :quantity 4}
{:code "bc22" :name "second nested name" :quantity 1}
{:code "lu32" :name "third nested name" :quantity 1}]})]
(s/setval [s/ATOM :lines s/ALL #(-> % :code (= "bc22")) :quantity] 10 *a))
您可以坚持使用 assoc-in
,但要这样做,您必须以某种方式从 :lines
字段的向量中检索与给定代码关联的索引。
例如,我要一个辅助函数:
(defn code->index [data code]
(->> data
:lines
(map-indexed (fn [i v] [i v]))
(filter (fn [[_ v]] (= (:code v) code)))
ffirst))
;; (code->index @my-atom "bc22")
;; => 1
然后在交换中使用它:
(swap! my-atom assoc-in [:lines (code->index @my-atom "bc22") :quantity] 10)
这里有选项。您可以查找项目的索引,可以映射列表,只更新您感兴趣的项目。
根据具体情况,您还可以考虑在呈现组件时存储元素的索引,或者构建一组 cursors 传递给您的组件。在那种情况下,您只需像更新原子一样更新游标,它会有效地处理更新支持原子。
就我个人而言,我看了这个并想知道您是否首先使用了正确的数据结构。 code
似乎很可能是这里的自然键,尤其是当您希望基于它更新一行时。也许以 code
为键、以整行为值的映射更有意义。这也使得某些不良情况不可能发生(e.x。多行具有相同的code
)。当然,您会丢失订单(除非您以某种方式 re-established 它),这可能是也可能不是问题。