2

I want to concatenate two ascii tables (one below the other) that share some but not all column headings.

e.g.

Table 1

Head1 HeadA
1     a
2     b

Table 2

HeadA HeadFoo
c     bar

And the result would be

Head1 HeadA HeadFoo
1     a
2     b
c           bar

There is a babel library which does not quite do this, but it may have some helper functions (which I can't locate in emacs 24.5, but I guess I could copy paste the lisp into a file and read it).

Regarding the answers: Both Gastove and Tobias' answers work correctly. I chose Tobias only because it is more "pure".

  • Is converting your ascii tables to Org tables an option? Do you need an elisp solution, or could you pass both tables in to an org-babel block that spits out the combined result? If so, you could do this in R or Python (happy to post an answer showing how). – Gastove Apr 1 '16 at 22:45
  • I worked on it a bit just now in a zsh script (stackoverflow.com/questions/36366948/…), so for this Q. i'm only interested in doing it in org-mode. I assumed I would convert to org tables and then convert back to ascii (cross that bridge when I get to it). That is, if you have a general non-emacs solution, post it on the other question :) – Alejandro Erickson Apr 1 '16 at 22:47
1

I just add an emacs-lisp version to Gastove's answer. The code block is executed when you put point on the #+BEGIN_SRC line and input C-c C-c.

  Table 1
  #+name: first_tab
  | Head1 | HeadA |
  |     1 | a     |
  |     2 | b     |

  Table 2
  #+name: second_tab
  | HeadA | HeadFoo |
  | c     | bar     |

  #+BEGIN_SRC emacs-lisp :var first_tab=first_tab second_tab=second_tab
(require 'cl-lib)
(let ((combined-header (cl-union (car second_tab) (car first_tab) :test 'string-equal))
      (tbl-rearrange (lambda (new-header tab)
               (let ((old-header (car tab)))
             ;; TODO: Consider 'hline.
             (cl-loop
              for row in (cdr tab)
              collect (let ((alist (cl-mapcar 'cons old-header row)))
                    (mapcar
                     (lambda (col) (or (cdr (assoc col alist)) ""))
                     new-header)))))))
  (append
   (list combined-header)
   (funcall tbl-rearrange combined-header first_tab)
   (funcall tbl-rearrange combined-header second_tab)))
  #+END_SRC

  #+RESULTS:
  | Head1 | HeadA | HeadFoo |
  |     1 | a     |         |
  |     2 | b     |         |
  |       | c     | bar     |
  • Being new to org I don't really know how to execute this. It might help me and future readers to have some of the basic details about that. I've got it in an emacs buffer in (Evil)Org mode... tried various commands that fuzzy match "orc src" but not working yet. Got by doing "org-babel-execute-src-block-maybe" on the lisp block. – Alejandro Erickson Apr 2 '16 at 9:40
  • @AlejandroErickson I do not know how key sequences are mapped by evil mode. In org mode most important things are done with the key sequence C-c C-c. The code block is executed when you put point on the #+BEGIN_SRC line and input C-c C-c. I add this to the answer. – Tobias Apr 2 '16 at 11:18
1

My answer is an R-in-org-babel approach:

#+name: first_tab
| Head1 | HeadA |
|     1 | a     |
|     2 | b     |

#+name: second_tab
| HeadA | HeadFoo |
| c     | bar     |

#+BEGIN_SRC R :var a=first_tab b=second_tab :colnames t
  dfa <- data.frame(a)
  dfb <- data.frame(b)

  ## Get all names
  allnames <- union(names(dfa), names(dfb))

  addmissing <- function(df, namevec) {
    missing <- setdiff(namevec, names(df))
    for (n in missing) {
      df[, n] <- NA
    }
    return(df)
  }

  newdfa <- addmissing(dfa, allnames)
  newdfb <- addmissing(dfb, allnames)

  res <- rbind(newdfa, newdfb)

  return(res)
#+END_SRC

#+RESULTS:
| Head1 | HeadA | HeadFoo |
|-------+-------+---------|
|     1 | a     | nil     |
|     2 | b     | nil     |
|   nil | c     | bar     |
  • Looks good. I'll test tomorrow if I can get R working via MacPorts. Will accept in a day or two. – Alejandro Erickson Apr 1 '16 at 23:24
  • You could do something comparable in Python with Pandas, if it's easier; you can even do this in elisp with a little gumption. – Gastove Apr 1 '16 at 23:33
  • ... or you can do this in elisp if it is easier;-). – Tobias Apr 2 '16 at 11:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.