0

I'm new to clojure and been trying to solve a problem where a vector of maps

({: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})

is given and i have to get a non overlapping data somewhat like

({: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})

I've tried using loop and recur but I think it's not possible to recur in both conditions of 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 Answers 2

1

To just answer the question (not looking into what you are trying to implement): you can recur in any tail position, and both branches of an if are in tail position. You just need to handle the base case before:

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

You would probably express this by branching for the argument to recur, however (but it works the same):

(loop [a arg]
  (if (base-case? a)
    a
    (recur (if (my-pred? a)
             (frob a)
             (whozzle a)))))
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this helps, actually i also wanted to display a map in both the cases of if along with recur.
0

Not directly answering your question but would like to offer a different approach to solve the problem:

(->> [{: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})

  • I am using integer as date in here to make it easier to read

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.