How can I open the TODO with the highest value of the property SWAY (integer) in org-agenda-files and that is tagged with "foobar"

The reason I ask is because the TODO with the highest SWAY is the TODO I'm working on, so it would be nice to bring it up quickly.

  • Try "TODO=\"TODO\"+SWAY>0" - see Matching tags and properties in the manual.
    – NickD
    Feb 16 at 16:02
  • BTW, you can get rid of the explicit file loop and have org-map-entries do all the work, by changing the scope to agenda.
    – NickD
    Feb 16 at 16:03
  • ;), Thanks again Feb 16 at 17:02

2 Answers 2


Thanks to NickD, here's a solution;)

(defun find-and-open-highest-sway-todo ()
  (let ((highest-sway 0)
        (highest-sway-marker nil))
    (dolist (file (org-agenda-files))
      (with-current-buffer (find-file-noselect file)
         (lambda ()
           (let ((sway-value (org-entry-get (point) "SWAY"))
                 (tags (org-get-tags)))
             (when (and sway-value (member "foobar" tags)) ;; Only process TODOs with both SWAY property and "foobar" tag
               (let ((sway-number (string-to-number sway-value)))
                 (when (> sway-number highest-sway)
                   (setq highest-sway sway-number)
                   (setq highest-sway-marker (point-marker)))))))
         "TODO=\"TODO\"" 'file))) ;; Only search for TODO entries
    (if highest-sway-marker
          (switch-to-buffer (marker-buffer highest-sway-marker))
          (goto-char highest-sway-marker)
          (message "Found TODO with highest SWAY value and 'foobar' tag: %d" highest-sway))
      (message "No TODOs with SWAY property and 'foobar' tag found."))))
  • You should have said ...here's a solution ...
    – NickD
    Feb 16 at 18:34
  • is it ok like this? Feb 16 at 18:45
  • All good :-) Good job!
    – NickD
    Feb 16 at 19:20

Here's another solution: it is a bit more general than the accepted solution but probably not as efficient, since it uses general mechanisms which are not tailored to the problem. It uses org-map-entries with the agenda scope, so we avoid having to loop over agenda files and it uses a match argument that filters precisely the relevant items. The idea is that the function that org-map-entries applies to each item returns a two-element list consisting of the value of the SWAY property and the point marker of the item; org-map-entries gathers all these into a list that is then sorted by the value of the SWAY property (the first element of each sublist) in descending order; the item with the maximum value of the SWAY property is then the first element of the sorted list. We then use the point-marker of that element to visit the file and go to the point that the marker tells us:

#+begin_src elisp :results drawer
  (defun my/todo-sway-items ()
    "Return a list of the SWAY property value and the point-marker
     of the item at point."
    (list (string-to-number (org-entry-get nil "SWAY")) (point-marker)))

  (defun find-and-open-highest-sway-todo ()
    "Call 'my/todo-sway-items' on all TODO items with a positive SWAY value
     in all agenda files. `org-map-entries' returns the list of these items
     which is sorted by SWAY value in descending order; the first item on
     that list then  has the highest SWAY value, so we extract its marker
     and visit it."
    (let ((max-sway-item (nth 0 (sort (org-map-entries #'my/todo-sway-items
                                      (lambda (x y) (> (nth 0 x) (nth 0 y)))))))
      (when max-sway-item
        (let ((marker (nth 1 max-sway-item)))
          (switch-to-buffer (marker-buffer marker))
          (goto-char marker)

The largest inefficiencies in this solution as compared to the OP's solution are:

  • the use of the matching expression in org-map-entries, in particular the SWAY > 0 part. Although that simplifies the program, the evaluation of the condition as not as efficient.

  • org-map-entries returns a list of all items with TODO="TODO" and SWAY>0. Since the OP has many such items, the list is likely to be long. Also, the largest element is obtained by sorting the list and carving off the first element. That is definitely not as efficient as the OP's program (which only keeps the largest element seen so far and does not worry about the rest). In addition, constructing a long list, sorting it and throwing most of it away will probably cause more garbage collections (perhaps a lot more) as compared to the OP's solution.

OTOH, the program is smaller (exluding comments, it's about half the size in LOC) and easier to modify for other purposes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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