I have a data structure like this:
[{ :2007-08-05 [ { :meat-weight-gain 100} {:meat-weight-loss 80} {:meat-balance 20}]},
{ :2007-08-06 [ { :meat-weight-gain 10} {:meat-weight-loss 60} {:meat-balance -30}]},
{ :2007-08-07 [ { :meat-weight-gain 40} {:meat-weight-loss 80} {:meat-balance -70}]}
{ :2007-08-08 [ { :meat-weight-gain 100} {:meat-weight-loss 0} {:meat-balance 30}]}]
How can i iterate through it and return the data period of when the meat balance was negative? A sample data would be something like this:
[ {:end-period-balance -70, :period-start 2007-08-06, :period-end 2007-08-07 } ]
Other than that, can I improve my data structure or it is already ok? If yes, how? Thank you very much.
i would advice you to change your data shape to a list of tuples, each containing date and map of balance data. Just like this:
(def data [[:2007-08-05 { :meat-weight-gain 100 :meat-weight-loss 80 :meat-balance 20}],
[:2007-08-06 { :meat-weight-gain 10 :meat-weight-loss 60 :meat-balance -30}],
[:2007-08-07 { :meat-weight-gain 40 :meat-weight-loss 80 :meat-balance -70}]
[:2007-08-08 { :meat-weight-gain 100 :meat-weight-loss 0 :meat-balance 30}]
[:2007-08-09 { :meat-weight-gain 19 :meat-weight-loss -20 :meat-balance -10}]])
then it would be easy to classify the periods by weight gain/loss (using partition-by
) and collect needed info:
user> (let [parts (partition-by #(-> % second :meat-balance neg?) data)]
(keep #(let [[p-start _] (first %)
[p-end {balance :meat-balance}] (last %)]
(when (neg? balance)
{:period-start p-start
:period-end p-end
:end-period-balance balance}))
parts))
;;=> ({:period-start :2007-08-06, :period-end :2007-08-07, :end-period-balance -70}
;; {:period-start :2007-08-09, :period-end :2007-08-09, :end-period-balance -10})
or a list of maps including date:
(def data [{:date :2007-08-05 :meat-weight-gain 100 :meat-weight-loss 80 :meat-balance 20},
{:date :2007-08-06 :meat-weight-gain 10 :meat-weight-loss 60 :meat-balance -30},
{:date :2007-08-07 :meat-weight-gain 40 :meat-weight-loss 80 :meat-balance -70}
{:date :2007-08-08 :meat-weight-gain 100 :meat-weight-loss 0 :meat-balance 30}
{:date :2007-08-09 :meat-weight-gain 100 :meat-weight-loss 0 :meat-balance -10}])
user> (let [parts (partition-by #(-> % :meat-balance neg?) data)]
(keep #(let [{p-start :date} (first %)
{p-end :date balance :meat-balance} (last %)]
(when (neg? balance)
{:period-start p-start
:period-end p-end
:end-period-balance balance}))
parts))
;;=> ({:period-start :2007-08-06, :period-end :2007-08-07, :end-period-balance -70}
;; {:period-start :2007-08-09, :period-end :2007-08-09, :end-period-balance -10})
UPDATE
if you really need your initial data format, then you can use the same approach, just redefining values retrieval parts:
user> (defn meat-balance [rec]
(some :meat-balance (-> rec first second)))
user> (let [parts (partition-by #(-> % meat-balance neg?) data)]
(keep #(let [p-start (-> % first ffirst)
p-end (-> % last ffirst)
balance (-> % first meat-balance)]
(when (neg? balance)
{:period-start p-start
:period-end p-end
:end-period-balance balance}))
parts))
;;=> ({:period-start :2007-08-06, :period-end :2007-08-07, :end-period-balance -30})