Я сделаю это с двумя функциями:
- Первая функция - это сокращение потребностей на основе одного источника
- Вторая функция использует вышеуказанную функцию для потребления списка поставок
(defn consume
"Reduce demands base on one supply"
[can-consume? demands supply]
(reduce (fn [{:keys [supply] :as ans} d]
(let [qty (:qty supply)]
(if (can-consume? d supply)
(let [used (-> d :qty (+ qty))]
(-> ans
(update :needs conj (assoc d :qty (min 0 used)))
(assoc-in [:supply :qty] (max 0 used))))
(update ans :needs conj d))))
;; initial state - no demands just one supply
{:needs []
:supply supply}
;; feed demands into reducing function
demands))
(defn consume-all
"Reduce demands with a list of supplies"
[{:keys [needs avails]}]
(->> (reduce (fn [ans s]
(let [{:keys [supply needs]
:as same-cat} (consume (fn [d s] (and (<= (:day s) (:day d))
(= (:cat s) (:cat d))))
(:needs ans)
s)
{:keys [supply needs]} (if supply ;; supply of same cat is consumed
same-cat
(consume (fn [d s] (<= (:day s) (:day d)))
(:needs ans)
s))]
(-> ans
(assoc :needs needs)
(update :avails conj supply))))
;; initial state - no supply only demands
{:needs needs
:avails []}
;; feed supplies into reducing function
avails)))
Бег с вашим образцом
(consume-all {:needs [{:day 20190107 :qty -100 :mkey "OS200" :cat " "}
{:day 20190108 :qty -50 :mkey "OS300" :cat " "}
{:day 20190109 :qty -100 :mkey "OS400" :cat " "}
{:day 20190217 :qty -100 :mkey "OS100" :cat "CO1"}]
:avails [{:day 20190101 :qty 10 :mkey "AAABB" :cat "CO1"}
{:day 20190101 :qty 20 :mkey "OS100" :cat "CO1"}
{:day 20190102 :qty 50 :mkey "OS200" :cat " "}
{:day 20190103 :qty 50 :mkey "OS300" :cat " "}
{:day 20190104 :qty 40 :mkey "OS400" :cat " "}]})
==>
{:needs
[{:day 20190107, :qty 0, :mkey "OS200", :cat " "}
{:day 20190108, :qty -10, :mkey "OS300", :cat " "}
{:day 20190109, :qty -100, :mkey "OS400", :cat " "}
{:day 20190217, :qty -70, :mkey "OS100", :cat "CO1"}],
:avails
[{:day 20190101, :qty 0, :mkey "AAABB", :cat "CO1"}
{:day 20190101, :qty 0, :mkey "OS100", :cat "CO1"}
{:day 20190102, :qty 0, :mkey "OS200", :cat " "}
{:day 20190103, :qty 0, :mkey "OS300", :cat " "}
{:day 20190104, :qty 0, :mkey "OS400", :cat " "}]}