Clojure - 使用列表和日期时间
Clojure - Working with list and date-time
我完全陷入了这种情况。
我有一个代表银行交易的原子列表。
(#<Ref@29a71299: {:desc "DESC1", :amount 150, :date #<LocalDate 2017-01-10>}>)
(#<Ref@5a4ebf03: {:desc "DESC2", :amount 250, :date #<LocalDate 2017-01-10>}>)
(#<Ref@5a4ebf03: {:desc "DESC3", :amount -250, :date #<LocalDate 2017-01-11>}>)
(#<Ref@5a4ebf03: {:desc "DESC4", :amount 50, :date #<LocalDate 2017-01-12>}>)
我需要在一天结束时计算账户余额,所以我应该抓取每天分开的所有交易以了解一天结束时的余额。
有人做过吗?筛选日期和进行计算的最佳方法是什么?我仍然 noob/student 在 clojure.
观察。我正在使用这个库处理日期 Jodatime
在 Clojure 中解决问题的一个好方法是思考:
- 如何分解这个问题(这通常是最难的部分)
- 我怎样才能一个人解决每一个问题
- 我如何编写这些解决方案(这通常是简单的部分)
将此应用于您的问题我发现了这些问题:
按其中一个键
的 属性 分割地图列表
(partition-by ... something ...)
对每个映射序列中的一个键的所有值求和
(map (reduce ...))
用每个段的数据和总和制作输出格式
(map ... something)
并且组成部分可能只是将其中的每一个嵌套为嵌套函数调用。嵌套函数调用可以使用 thread-last maco 编写,看起来像这样:
(->> data
(... problem one solution ...)
(problem two solution)
(some output formatting for problem three))
这最终变得比我想象的要复杂。我查看了 partition-by
,您几乎肯定应该改用它。它非常适合这个问题。这只是一个示例,说明如何使用 loop
:
(defn split-dates [rows]
(loop [[row & rest-rows] rows ; Split on the head
last-date nil
acc [[]]]
(if row
(let [current-date (last row)]
(recur rest-rows current-date
; If the day is the same as the previous row
(if (or (nil? last-date) (= current-date last-date))
; Update the current day list with the new row
(update acc (dec (count acc))
#(conj % row))
; Else, create a new list of rows for the new date
(conj acc [row]))))
acc)))
(clojure.pprint/pprint
(split-dates
[[0 1 "16.12.25"]
[2 3 "16.12.25"]
[4 5 "16.12.26"]
[6 7 "16.12.26"]
[8 9 "16.12.26"]
[1 9 "16.12.27"]]))
[[[0 1 "16.12.25"] [2 3 "16.12.25"]]
[[4 5 "16.12.26"] [6 7 "16.12.26"] [8 9 "16.12.26"]]
[[1 9 "16.12.27"]]]
备注:
假设日期在最后一列,并且行按日期排序。
它 returns [[]]
当给定一个空列表时。这可能是也可能不是您想要的。
你可能想这样分解:
(defn per-day-balance [txns]
(->> txns
(partition-by :date)
(map (fn [[{date :date} :as txns]]
{:date date :balance (reduce + (map :amt txns))}))))
假设每天从 0 开始计算每日余额。示例 运行:
(def txns [{:date 1 :amt 10}
{:date 1 :amt 3}
{:date 2 :amt 9}
{:date 2 :amt -11}
{:date 3 :amt 13}])
user> (per-day-balance txns)
=> ({:date 1, :balance 13} {:date 2, :balance -2} {:date 3, :balance 13})
现在添加一个缩减函数以获得 运行ning 总数。减少功能只是'update' 累积余额:
(defn running-balance [bals]
(let [[day-1 & others] bals]
(reductions
(fn [{running :balance} e] (update e :balance + running))
day-1
others)))
样本运行:
user> (->> txns
per-day-balance
running-balance)
=> ({:date 1, :balance 13} {:date 2, :balance 11} {:date 3, :balance 24})
注意:您可以为 :date 字段使用任何数据类型。其次,我有意避免使用 atom 来使函数变得纯粹。
我完全陷入了这种情况。 我有一个代表银行交易的原子列表。
(#<Ref@29a71299: {:desc "DESC1", :amount 150, :date #<LocalDate 2017-01-10>}>)
(#<Ref@5a4ebf03: {:desc "DESC2", :amount 250, :date #<LocalDate 2017-01-10>}>)
(#<Ref@5a4ebf03: {:desc "DESC3", :amount -250, :date #<LocalDate 2017-01-11>}>)
(#<Ref@5a4ebf03: {:desc "DESC4", :amount 50, :date #<LocalDate 2017-01-12>}>)
我需要在一天结束时计算账户余额,所以我应该抓取每天分开的所有交易以了解一天结束时的余额。
有人做过吗?筛选日期和进行计算的最佳方法是什么?我仍然 noob/student 在 clojure.
观察。我正在使用这个库处理日期 Jodatime
在 Clojure 中解决问题的一个好方法是思考:
- 如何分解这个问题(这通常是最难的部分)
- 我怎样才能一个人解决每一个问题
- 我如何编写这些解决方案(这通常是简单的部分)
将此应用于您的问题我发现了这些问题:
按其中一个键
的 属性 分割地图列表(partition-by ... something ...)
对每个映射序列中的一个键的所有值求和
(map (reduce ...))
用每个段的数据和总和制作输出格式
(map ... something)
并且组成部分可能只是将其中的每一个嵌套为嵌套函数调用。嵌套函数调用可以使用 thread-last maco 编写,看起来像这样:
(->> data
(... problem one solution ...)
(problem two solution)
(some output formatting for problem three))
这最终变得比我想象的要复杂。我查看了 partition-by
,您几乎肯定应该改用它。它非常适合这个问题。这只是一个示例,说明如何使用 loop
:
(defn split-dates [rows]
(loop [[row & rest-rows] rows ; Split on the head
last-date nil
acc [[]]]
(if row
(let [current-date (last row)]
(recur rest-rows current-date
; If the day is the same as the previous row
(if (or (nil? last-date) (= current-date last-date))
; Update the current day list with the new row
(update acc (dec (count acc))
#(conj % row))
; Else, create a new list of rows for the new date
(conj acc [row]))))
acc)))
(clojure.pprint/pprint
(split-dates
[[0 1 "16.12.25"]
[2 3 "16.12.25"]
[4 5 "16.12.26"]
[6 7 "16.12.26"]
[8 9 "16.12.26"]
[1 9 "16.12.27"]]))
[[[0 1 "16.12.25"] [2 3 "16.12.25"]]
[[4 5 "16.12.26"] [6 7 "16.12.26"] [8 9 "16.12.26"]]
[[1 9 "16.12.27"]]]
备注:
假设日期在最后一列,并且行按日期排序。
它 returns
[[]]
当给定一个空列表时。这可能是也可能不是您想要的。
你可能想这样分解:
(defn per-day-balance [txns]
(->> txns
(partition-by :date)
(map (fn [[{date :date} :as txns]]
{:date date :balance (reduce + (map :amt txns))}))))
假设每天从 0 开始计算每日余额。示例 运行:
(def txns [{:date 1 :amt 10}
{:date 1 :amt 3}
{:date 2 :amt 9}
{:date 2 :amt -11}
{:date 3 :amt 13}])
user> (per-day-balance txns)
=> ({:date 1, :balance 13} {:date 2, :balance -2} {:date 3, :balance 13})
现在添加一个缩减函数以获得 运行ning 总数。减少功能只是'update' 累积余额:
(defn running-balance [bals]
(let [[day-1 & others] bals]
(reductions
(fn [{running :balance} e] (update e :balance + running))
day-1
others)))
样本运行:
user> (->> txns
per-day-balance
running-balance)
=> ({:date 1, :balance 13} {:date 2, :balance 11} {:date 3, :balance 24})
注意:您可以为 :date 字段使用任何数据类型。其次,我有意避免使用 atom 来使函数变得纯粹。