Question

I have a list in Elisp. How do i return a list consisting of every nth element starting from the 1st? In Python i have slice notation:

>>> range(10)[::3]
[0, 3, 6, 9]

I can't find anything helpful in dash.el list API, so i wrote my solution using loop macro:

(defun step (n xs)
  (loop for x in xs by (lambda (xs) (nthcdr n xs))
        collect x))

ELISP> (step 3 (number-sequence 0 10))
(0 3 6 9)

By the way, (lambda (xs) (nthcdr n xs)) could be rewritten with dash.el's partial application function -partial: (-partial 'nthcdr n).

loop macro seems like overkill. How do i return elements by step in Emacs Lisp?

Was it helpful?

Solution

dash package's slice supports step from version 2.7. Therefore Python's range(10)[1:7:2] is equivalent to:

(-slice (number-sequence 0 9) 1 7 2) ; (1 3 5)

OTHER TIPS

Here's a short illustration, comparing using -partial and a plain lambda in a loop:

(require 'cl-lib)

(prog1 nil
  (setq bigdata (number-sequence 1 10000)))

(defun every-nth-1 (n xs)
  (cl-loop for x in xs by (lambda (xs) (nthcdr n xs))
     collect x))

(defun every-nth-2 (n xs)
  (cl-loop for x in xs by (-partial 'nthcdr n)
     collect x))

(defmacro util-timeit (expr)
  (let ((t-beg (float-time))
        (res (dotimes (i 1000)
               (eval expr)))
        (t-end (float-time)))
    (/
     (- t-end t-beg)
     1000)))

(setq time1
      (util-timeit
       (length (every-nth-1 3 bigdata))))

(setq time2
      (util-timeit
       (every-nth-2 3 bigdata)))

(message "%s" (/ time2 time1))

Calling eval-buffer gives me a result around 4. This means that (lambda (xs) (nthcdr n xs)) is 4 times faster than (-partial 'nthcdr n), at least without byte compilation.

With byte-compilation, it gives an astounding 12.2-13.6 times difference in performance in favor of a plain lambda!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top