Clojure: повторение цикла в обоих условиях «IF» - PullRequest
0 голосов
/ 25 марта 2019

Я новичок в замыкании и пытаюсь решить проблему с вектором карт

({:disease Asthma, :st-dt 2018-2-1, :en-dt 2018-4-1, :dose 0.25} 
{:disease Asthma, :st-dt 2018-3-1, :en-dt 2018-6-5, :dose 0.65} 
{:disease BP, :st-dt 2018-5-1, :en-dt 2018-9-1, :dose 0.75})
* Дано

, и я должен получить непересекающиеся данные, вроде

({:disease Asthma, :st-dt 2018-2-1, :en-dt 2018-2-28, :dose 0.25} 
{:disease Asthma, :st-dt 2018-3-1, :en-dt 2018-4-1, :dose 0.25} 
{:disease Asthma, :st-dt 2018-3-1, :en-dt 2018-4-1, :dose 0.65} 
{:disease Asthma, :st-dt 2018-4-2, :en-dt 2018-4-30, :dose 0.65} 
{:disease Asthma, :st-dt 2018-5-1, :en-dt 2018-6-5, :dose 0.65} 
{:disease BP, :st-dt 2018-5-1, :en-dt 2018-6-5, :dose 0.75}
{:disease BP, :st-dt 2018-6-6, :en-dt 2018-9-1, :dose 0.75})

Я пытался использовать loop и recur, но я думаю, что невозможно повторить в обоих условиях if.

(defn ab [x] (let [temp x olap (f/overlap (f/interval ((first temp ):st-dt) ((first temp ):en-dt)) 
                                          (f/interval ((second temp):st-dt) ((second temp):en-dt) ))]
               (if olap 
                 (into [] (concat [{:med-type ((first temp ):med-type) :st-dt ((first temp ):st-dt)
                                    :en-dt (f/minus ((second temp) :st-dt) (f/days 1)) :dose ((first temp):dose )}
                                   {:med-type ((first temp ):med-type) :st-dt ((second temp ):st-dt)
                                    :en-dt ((first temp) :en-dt) :dose ((first temp):dose )}
                                   {:med-type ((second temp ):med-type) :st-dt ((second temp ):st-dt)
                                    :en-dt ((first temp) :en-dt) :dose ((second temp):dose )}
                                   {:med-type ((second temp ):med-type) :st-dt (f/plus ((first temp ):en-dt) (f/days 1))
                                    :en-dt ((second temp) :en-dt) :dose ((second temp):dose )}] 
                                  (into [] (rest (rest x))))))))

Ответы [ 2 ]

1 голос
/ 25 марта 2019

Чтобы просто ответить на вопрос (не смотря на то, что вы пытаетесь реализовать): вы можете повторяться в любой хвостовой позиции, и обе ветви if находятся в хвостовой позиции. Вам просто нужно обработать базовый вариант до:

(loop [a arg]
  (if (base-case? a)
    a
    (if (my-pred? a)
      (recur (frob a))
      (recur (whozzle a)))))

Вы, вероятно, могли бы выразить это путем разветвления аргумента для повторения, однако (но он работает так же):

(loop [a arg]
  (if (base-case? a)
    a
    (recur (if (my-pred? a)
             (frob a)
             (whozzle a)))))
0 голосов
/ 29 марта 2019

Непосредственно не отвечая на ваш вопрос, но хотел бы предложить другой подход для решения проблемы:

(->> [{:disease :Asthma :start 20 :end 41 :dose 0.25}
      {:disease :Asthma :start 31 :end 65 :dose 0.65}
      {:disease :BP :start 51 :end 91 :dose 0.75}]

     ;; EXPAND TO DATE SEQUENCE
     ;;
     (mapcat (fn [{:keys [start end] :as d}]
               (let [x (dissoc d :start :end)]
                 (map (partial assoc x :dt) (range start end)))))
     (sort-by :dt)

     ;; ({:disease :Asthma, :dose 0.25, :dt 20}
     ;;  {:disease :Asthma, :dose 0.25, :dt 21}
     ;;  {:disease :Asthma, :dose 0.25, :dt 22}

     ;; 'GROUP' SUBSCRIPTIONS BY DATE
     ;;
     (partition-by :dt)
     (map #(reduce (fn [s e] (update s :subscriptions conj (dissoc e :dt)))
                   {:subscriptions #{}
                    :dt            (-> % first :dt)}
                  %))
     (partition-by :subscriptions)

     ;; (({:subscriptions #{{:disease :Asthma, :dose 0.25}}, :dt 20}
     ;;   ...
     ;;   {:subscriptions #{{:disease :Asthma, :dose 0.25}}, :dt 30})
     ;;  ({:subscriptions
     ;;    #{{:disease :Asthma, :dose 0.25} {:disease :Asthma, :dose 0.65}},
     ;;    :dt 31}
     ;;    ...
     ;;   {:subscriptions
     ;;    #{{:disease :Asthma, :dose 0.25} {:disease :Asthma, :dose 0.65}},
     ;;    :dt 40})

     ;; GET BACK DATE RANGE FROM PARTITIONS OF SUBSCRIPTIONS
     ;;
     (map #(-> %
               first
               (dissoc :dt)
               (assoc :start (-> % first :dt)
                      :end (-> % last :dt))))

     ;; ({:subscriptions #{{:disease :Asthma, :dose 0.25}}, :start 20, :end 30}
     ;;  {:subscriptions
     ;;   #{{:disease :Asthma, :dose 0.25} {:disease :Asthma, :dose 0.65}},
     ;;   :start 31,
     ;;   :end 40}


     ;; FLATTEN THE LIST BY SUBSCRIPTIONS
     ;;
     (mapcat (fn [{:keys [subscriptions start end]}]
               (map #(assoc % :start start :end end) subscriptions)))
     (sort-by (juxt :start :disease :dose)))

    ;; ({:disease :Asthma, :dose 0.25, :start 20, :end 30}
    ;;  {:disease :Asthma, :dose 0.25, :start 31, :end 40}
    ;;  {:disease :Asthma, :dose 0.65, :start 31, :end 40}
    ;;  {:disease :Asthma, :dose 0.65, :start 41, :end 50}
    ;;  {:disease :Asthma, :dose 0.65, :start 51, :end 64}
    ;;  {:disease :BP, :dose 0.75, :start 51, :end 64}
    ;;  {:disease :BP, :dose 0.75, :start 65, :end 90})

  • Я использую здесь целое число в качестве даты, чтобы было легче читать
...