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 中解决问题的一个好方法是思考:

  1. 如何分解这个问题(这通常是最难的部分)
  2. 我怎样才能一个人解决每一个问题
  3. 我如何编写这些解决方案(这通常是简单的部分)

将此应用于您的问题我发现了这些问题:

  • 按其中一个键

    的 属性 分割地图列表

    (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 来使函数变得纯粹。