6

Is there a simpler way to remove the last element of a list than this?

(setq list (reverse (cdr (reverse list))))
  • 1
    If doing that, you would likely want to be using nreverse (destructive) rather than reverse (copying), for the sake of efficiency. – phils May 22 at 4:16
10

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:

  • if you are in a pure function (you have local non-leaking bindings)
  • you generate the list from its elements within the function
  • you want to split off the last element at the end of the function (i.e. in the last evaluated form before exiting the function)

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)
  • 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). – phils May 22 at 4:09
  • Note that behind the scenes, these functions are using setcdr to modify the nthcdr where N is based on the length of the list. – phils May 22 at 4:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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