функциональный способ балансировки двух векторов в clojure - PullRequest
0 голосов
/ 06 февраля 2019

Я бы сбалансировал два вектора, представляющих потребности и доступность продукта.

Это каноническая проблема в планировании потребности в материалах, очень простая в императивном стиле.Возможно ли это в функциональном программировании?

Я должен перейти от А1 к А2 со следующим приоритетом: сначала присвоить aval qty для записей с одинаковым: cat, затем для потребностей в начале: day.

формат для: день AAAAMMDD

(def A1
  {:avail [{: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 -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"}]})


(def A2
  {:avail [{: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 "   "}]

   :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"}]})

возможный Java-алгоритм для получения A2 из A1

ArrayList avail = new ArrayList();
ArrayList needs = new ArrayList();
/* first assign based on same :cat */
for (int i=0;i< needs.size();i++) {
    // get needs record of index i..
    for (int j=0;j< avail.size();j++) {
         // get avail record of index j..
         if (need.cat != avail.cat)  // only same same cat ! 
                continue;
         balance the actuals records needs and avail
         updating relative qty, 
         trying to set need qty to zero decrementing avail
    }
}
/* now again without test on cat */
for (int i=0;i< needs.size();i++) {
    // get needs record of index i..
    for (int j=0;j< avail.size();j++) {
         // get avail record of index j..
         balance the actuals records needs and avail
         updating relative qty 
         trying to set need qty to zero decrementing avail
    }
}

1 Ответ

0 голосов
/ 07 февраля 2019

Я сделаю это с двумя функциями:

  1. Первая функция - это сокращение потребностей на основе одного источника
  2. Вторая функция использует вышеуказанную функцию для потребления списка поставок
(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 "   "}]}

...