Sorting citation links by year

| categories: bibtex | tags:

When there are several citations grouped together, I like them sorted by year. For example, I do not like this liu-2014-spect-studies,mcalpin-2010-epr-eviden,kanan-2009-cobal,lutterman-2009-self-healin,kanan-2008-in-situ. I prefer kanan-2008-in-situ,kanan-2009-cobal,lutterman-2009-self-healin,mcalpin-2010-epr-eviden,liu-2014-spect-studies. It is just a preference, but it seems appropriate to cite things in chronological order.

It is actually a little tedious to sort this by hand though. Hence, today we examine some tools to automate the sorting. The idea is to make a function that will get the keys, sort them by year, and then replace the link with the sorted text.

Let us try some sorting. We will construct a set of cons cells with a year and key, sort that list by year, and then concatenate the keys. Here is an example of the sorting. The years will come as strings from the bibtex file.

(setq data '(("2014" . "key1") ("2012" . "key2")("2016" . "key3")))
(setq data 
	(cl-sort data (lambda (x y) (< (string-to-int (car x)) (string-to-int (car y))))))
(mapconcat (lambda (x) (cdr x)) data ",")

That is easy enough. Now, a function to get the year, and then the function to sort a link.

(defun org-ref-get-citation-year (key)
  "get the year of an entry with key"
  (let* ((results (org-ref-get-bibtex-key-and-file key))
	 (bibfile (cdr results))
	 (cb (current-buffer)))
    (message "---------%s %s" key bibfile)
    (set-buffer (find-file-noselect bibfile))
    (bibtex-search-entry key nil 0)
    (prog1 (reftex-get-bib-field "year" (bibtex-parse-entry t))
      (set-buffer cb))))

(defun org-ref-sort-citation-link ()
 "replace link at point with sorted link by year"
 (let* ((object (org-element-context))	 
        (type (org-element-property :type object))
	(begin (org-element-property :begin object))
	(end (org-element-property :end object))
	(link-string (org-element-property :path object))
	keys years data)
  (setq keys (org-ref-split-and-strip-string link-string))
  (setq years (mapcar 'org-ref-get-citation-year keys)) 
  (setq data (mapcar* (lambda (a b) `(,a . ,b)) years keys))
  (setq data (cl-sort data (lambda (x y) (< (string-to-int (car x)) (string-to-int (car y))))))
  ;; now get the keys separated by commas
  (setq keys (mapconcat (lambda (x) (cdr x)) data ","))
  ;; and replace the link with the sorted keys
  (cl--set-buffer-substring begin end (concat type ":" keys))

Now, you put your cursor on a link, run M-x org-ref-sort-citation-link, and the magic happens kanan-2008-in-situ,kanan-2009-cobal,lutterman-2009-self-healin,mcalpin-2010-epr-eviden,liu-2014-spect-studies! It would also be nice to have some arrow commands so you could do something like manually reorder them with S-arrow or something like in the calendar, but that will be another day.

Copyright (C) 2014 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.6

Discuss on Twitter