Reputation: 873
Data in an org table can be processed (row-by-row) in src blocks like so:
#+NAME: test-table
| a | b |
|---+---|
| 1 | 2 |
| 3 | 4 |
#+NAME: test-table-script
#+BEGIN_SRC emacs-lisp :var table=test-table
(mapcar (lambda (x) (cadr x)) table)
#+END_SRC
#+RESULTS: test-table-script
| 2 | 4 |
In the example above, though, the table is only available through the table
variable, and I have to pull the elements in each row/column out manually.
In the case that the original table has column names (as in the case above) is there a way to have the values columns of the table automatically bound to those variables (a
and b
in the example table) in a BEGIN_SRC
block?
Upvotes: 1
Views: 908
Reputation: 130
The following solution uses org-babel-get-colnames
and cl-destructuring-bind
. Note that the table colnames are strings and need to be interned. The example shows the original data with an additional column.
#+NAME: test-table-script
#+BEGIN_SRC emacs-lisp :var table=test-table :colnames no
(require 'cl)
(defmacro with-table (table expression)
"Given an org table with colnames, evaluate an expression using the colnames.
Note: use ':colnames no' in the header -- this imports the colnames
but does not export them."
`(let* ((table-with-colnames (org-babel-get-colnames ,table))
(names (loop for name in (cdr table-with-colnames)
collect (if (stringp name) (intern name) name))))
(funcall
`(lambda (data)
(mapcar (lambda (row)
(cl-destructuring-bind ,names row ,',expression))
data))
(car table-with-colnames))))
;; example to add a third column
(cons '(a b c) (cons 'hline (with-table table (list a b (+ a b)))))
#+END_SRC
With output:
#+RESULTS: test-table-script
| a | b | c |
|---+---+---|
| 1 | 2 | 3 |
| 3 | 4 | 7 |
This approach could be readily extended to transform columns, either replacing values or adding a new column. The macro could also be improved through the addition of some gensym's.
Upvotes: 1