org-randomnote icon indicating copy to clipboard operation
org-randomnote copied to clipboard

Suggestion

Open alphapapa opened this issue 6 years ago • 8 comments

Hi,

I ran across this package the other day and have a small suggestion. You currently use org-map-entries with line-number-at-pos, which is convenient, but slow, as it has to map across every entry in the file, whether it will be used or not.

Instead, you can use a simpler algorithm within a file which will be much faster, like this:

(defun ap/org-random-heading (top-level)
  "Go to random heading in current buffer."
  (interactive "P")
  (goto-char (random (buffer-size)))
  (if (org-before-first-heading-p)
      (outline-next-heading)
    (org-back-to-heading)
    (when top-level
      (cl-loop until (not (org-up-heading-safe))))))

And with a prefix arg, you can make it go to only top-level headings.

alphapapa avatar Jun 12 '18 15:06 alphapapa

Wonderful! Would you like to submit a PR with this change?

mwfogleman avatar Jun 12 '18 16:06 mwfogleman

No, thank you, because I just use this function directly from my own config. :) Just thought I'd share it in case you find it useful.

alphapapa avatar Jun 12 '18 17:06 alphapapa

Question - wouldn't this implementation have the downside of making the function less random, in that headings with larger content would be more likely to come up?

mwfogleman avatar Jun 12 '18 18:06 mwfogleman

I hadn't thought of that. I suppose you're right. Good catch. Of course, in most cases, the performance difference probably doesn't matter. In larger files (e.g. I have a large one with 1800+ headings), it might be preferable. So I guess it depends on how big your files are and how much of a probability purist you are, haha. ;)

alphapapa avatar Jun 12 '18 20:06 alphapapa

BTW, another approach, which would be slower than this but faster than org-map-entries, and which shouldn't be biased toward large entries, would be to do a regexp search through the file looking for lines starting with * , collect the positions, and choose a random one. Something like:

(defun org-random-entry ()
  (interactive)
  (widen)
  (goto-char (point-min))
  (cl-loop while (re-search-forward (rx bol "* ") nil t)
           collect (point) into positions
           finally do (progn
                        (goto-char (seq-random-elt positions))
                        (org-reveal))))

alphapapa avatar Nov 19 '18 04:11 alphapapa

Thank you! I am very open to this implementation change. Is there a way to profile the default implementation vs this alternate implementation? If someone sends that and a PR I will accept it.

On Sun, Nov 18, 2018 at 8:56 PM alphapapa [email protected] wrote:

BTW, another approach, which would be slower than this but faster than org-map-entries, and which shouldn't be biased toward large entries, would be to do a regexp search through the file looking for lines starting with * , collect the positions, and choose a random one. Something like:

(defun org-random-entry () (interactive) (widen) (goto-char (point-min)) (cl-loop while (re-search-forward (rx bol "* ") nil t) collect (point) into positions finally do (progn (goto-char (seq-random-elt positions)) (org-reveal))))

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/mwfogleman/org-randomnote/issues/4#issuecomment-439771761, or mute the thread https://github.com/notifications/unsubscribe-auth/ACuwIimh-1EFHijKq8051fgZJ1iLZJtRks5uwjn8gaJpZM4UkppU .

-- Tasshin Michael Fogleman Website https://www.tasshin.com/ | Hostwriting http://www.hostwriting.com/ | Mind Body Attention http://mindbodyattention.com/

mwfogleman avatar Nov 19 '18 15:11 mwfogleman

See the bench-multi macro at https://alphapapa.github.io/emacs-package-dev-handbook

alphapapa avatar Nov 19 '18 22:11 alphapapa

As mentioned at https://github.com/melpa/melpa/pull/6603#issuecomment-569169666, here's an implementation that uses org-ql. It's simple, fast, flexible, and should be evenly weighted:

(cl-defun org-goto-random-heading (&key (buffers (list (current-buffer)))
                                        regexp)
  (let* ((entries (org-ql-select buffers
                    `(regexp ,regexp)
                    :action '(cons (current-buffer) (point))))
         (entry (seq-random-elt entries)))
    (pop-to-buffer (car entry))
    (goto-char (cdr entry))))

Use it like:

(org-goto-random-heading :buffers "~/org/main.org" :regexp "Emacs")

alphapapa avatar Dec 27 '19 02:12 alphapapa