Is there a simpler way to remove the last element of a list than this?
(setq list (reverse (cdr (reverse list))))
Yes there is:
(setq list (butlast list))
That is a function from subr.el
. (Loaded by default. No need to load anything.)
You can also cut a tail with N
elements by
(setq list (butlast list N))
A word about phils' comment:
If it's safe to modify the original list structure, then
nbutlast
will be slightly more efficient (n.b. you still need to assign the result back to the variable).
The comment is right and useful but it has to be considered very cautious.
For an exmple the application of nbutlast
is safe if the following three conditions are fulfilled:
Be aware that nbutlast
modifies the argument list
in the calls of the following functions!
(defun queue (el list)
"Prepend el and remove last element."
(nbutlast (cons el list)))
(defun foo (head list)
"Prepend head and remove last element."
(nbutlast (append head list)))
(setq list (list 2 3 4))
(queue 1 list)
list ;; -> (2 3)
(foo '(1) list)
list ;; -> (2)
nbutlast
will be slightly more efficient (n.b. you still need to assign the result back to the variable).
setcdr
to modify the nthcdr
where N is based on the length
of the list.
Another solution would be to use dash.el
's slicing:
(setq list (-slice 0 -1 list))
I don't know if this is too much 'soy' for those hardcore lispers, but -slice
really takes the hassle out of lists for me. ;)
The sequences library bundled with Emacs makes this easily generalized. Here I demonstrate a possible implementation in an IELM buffer.
ELISP> (defun seq-butlast-elt (seq)
"Return a copy of SEQ without its final element."
(seq-take seq (1- (seq-length seq))))
seq-butlast-elt
ELISP> (seq-butlast-elt '(1 2 3))
(1 2)
ELISP> (seq-butlast-elt '(1))
nil
ELISP> (seq-butlast-elt '())
nil
ELISP> (seq-butlast-elt ["oak" "cherry" "apple"])
["oak" "cherry"]
ELISP> (seq-butlast-elt ["apple"])
[]
ELISP> (seq-butlast-elt [])
[]
ELISP> (seq-butlast-elt "dogs")
"dog"
ELISP> (seq-butlast-elt "d")
""
ELISP> (seq-butlast-elt "")
""
https://www.gnu.org/software/emacs/manual/html_node/elisp/Sequence-Functions.html
This might not be the fastest possible implementation.
nreverse
(destructive) rather thanreverse
(copying), for the sake of efficiency.