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?
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)
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With