clojure - 转换具有变化状态的序列的功能/clojure方式是什么?
问题描述
问题背景与股票交易有关。当进行销售时,我正在尝试更新特定股票的持有量。简化摘录
;; @holdings - an atom
{ "STOCK1" {:trades [Trade#{:id 100 :qty 50}, Trade#{ :id 140 :qty 50}]}
"STOCK2" ... }
现在给出 的卖出交易Trade{:id 200 :stock "STOCK1", :qty 75}
,我预计持股会反映
{ "STOCK1" {:trades [Trade#{:id 100 :qty 0}, Trade#{ :id 140 :qty 25}]} }
;; or better drop the records with zero qty.
{ "STOCK1" {:trades [Trade#{ :id 140 :qty 25}]} }
功能性的答案让我望而却步.. 我所看到的只是一个doseq
带有原子的循环来保持状态(例如 sale-qty 可能由 1 或 n 次交易满足) - 但它感觉就像 Clojure 中的 C。
有没有更符合clojure的解决方案?地图看起来不合适,因为每个记录处理都需要更新外部状态(待售数量 75 -> 25 -> 0)
免责声明:想学习的 Clojure 新手。
解决方案
(require '[com.rpl.specter :as s])
(let [stocks {"STOCK1" {:trades [{:trade/id 100 :trade/qty 50}, {:trade/id 140 :trade/qty 50}]}}
sale-trade {:trade/id 200 :trade/stock "STOCK1" :trade/qty 75}
trade-path [(s/keypath (:trade/stock sale-trade) :trades) s/ALL]
qty-path (conj trade-path :trade/qty)
[new-qty _] (reduce (fn [[new-amounts leftover] v]
(let [due-amount (min v leftover)]
[(conj new-amounts (- v due-amount)) (- leftover due-amount)]))
[[] (:trade/qty sale-trade)]
(s/select qty-path stocks))]
(->> stocks
(s/setval (s/subselect qty-path) new-qty)
(s/setval [trade-path #(zero? (:trade/qty %))] s/NONE)))
=> {"STOCK1" {:trades [#:trade{:id 140, :qty 25}]}}
推荐阅读
- typescript - 访问 Typescript 中变量的允许值之一
- sql-server - 将 Azure SQL 连接到本地外部表错误:发生与网络相关或特定于实例的错误
- android - OpenGL:根据刷新率创建一个闪烁的黑/白屏幕(移动)
- javascript - 扁平化数组树js
- python - 在 Optuna 研究期间动态添加/删除参数时会发生什么?
- python - 访问使用 for 循环创建的条目小部件数据以进行绘图
- java - OSPermissionSubscriptionState:无法解析符号
- python - 当我尝试删除所有不以特定名称开头的行时,如何将列名保留在数据框中?
- python-3.x - 将操作应用于 numpy 数组中的特定列
- jackson - 字符串的杰克逊反序列化为 LocalDateTime 不一致