Using Emacs Org Mode tables to calculate doses to buy
Posted: - Modified: | emacs, orgI got tired of manually calculating how many I needed to buy based on a daily protocol and how many I had in stock, so I wrote a little bit of Emacs Lisp to figure it out. You can specify the type, daily dose, start and end dates (inclusive; defaults to the last specified date if blank), and how many you have in stock.
First, define a table of this form, and give it a name.
| Type | Per day | Start | End | Stock | |--------------+---------+------------+------------+-------| | Medication A | 2 | 2015-06-09 | 2015-06-16 | 5 | | Medication B | 1 | | | 0 | | Medication C | 0.1 | 2015-06-12 | 2015-06-16 | 0.2 |
Type | Per day | Start | End | Stock |
---|---|---|---|---|
Medication A | 2 | 2015-06-09 | 2015-06-16 | 5 |
Medication B | 1 | 0 | ||
Medication C | 0.1 | 2015-06-12 | 2015-06-16 | 0.2 |
To call the code from the bottom of this post, use something like:
#+CALL: calculate-meds-needed(meds=input) :hlines yes :colnames yes
Type | Total | In stock | Needed |
---|---|---|---|
Medication A | 16 | 5 | 11 |
Medication B | 8 | 0 | 8 |
Medication C | 0.5 | 0.2 | 1 |
Here’s the code that processes it:
#+begin_src emacs-lisp (let (start end) (append (list (list "Type" "Total" "In stock" "Needed")) (list 'hline) (sort (delq nil (mapcar (lambda (row) (unless (or (eq row 'hline) (string= (elt row 0) "Type")) (let (total) (setq start (if (string< "" (elt row 3)) (elt row 3) start) end (if (string< "" (elt row 2)) (elt row 2) end) total (* (elt row 1) (- (calendar-absolute-from-gregorian (org-date-to-gregorian start)) (calendar-absolute-from-gregorian (org-date-to-gregorian end)) -1))) (list (elt row 0) total (elt row 4) (max 0 (ceiling (- total (elt row 4)))))))) meds)) (lambda (a b) (string< (car a) (car b)))))) #+end_src
You can comment with Disqus or you can e-mail me at sacha@sachachua.com.