Removing the last two items from a list in Lisp

I need to remove the last two items from a list in the general list, but I can only remove one. How?

(defun my-butlast (list)
        (loop for l on list
              while (rest l)
              collect (first l)))

      

+3


source to share


2 answers


Simple: reverse, pop, pop, reverse ;-) 1

More efficiently, the following also works:

(let ((list '(a b c d)))
  (loop 
    for x in list
    for y in (cddr list)
    collect x))

      

This can also be written for some arbitrary L and N:

(mapcar #'values L (nthcdr N L)) 

      



This works because iterating over multiple lists is limited to the shortest one. The length of the second list is important here (we don't care about its values), that is, the length of the original list minus N when this value is positive, or zero otherwise. Note that NTHCDR

it is convenient to work with sizes larger than the length of the list specified in the argument. In the second example, I use the function VALUES

as a generic identity function; MAPCAR

only uses the base value of the computed values, so this works as desired. The behavior is compatible with the actual function 2, which returns for N more than the number of elements in the list. Actual functionBUTLAST

nil

BUTLAST

can also handle invalid (dashed) lists, but the above version cannot.


1. (alexandria:compose #'nreverse #'cddr #'reverse)

2. is BUTLAST

indicated as equivalent (ldiff list (last list n))

. I completely forgot about existence LDIFF

!

+4


source


The standard has a function: butlast or if you want to change the nbutlast input list .

butlast returns a copy of the list from which the last n conses have been omitted. If n is not supplied, its value is 1. If there are fewer than n conses in the list, nil is returned, and in the case of nbutlast, the list is unchanged.

nbutlast is like butlast, but nbutlast can modify the list. It changes cdr from cons n + 1 from the end of the list to nil.

Examples:



CL-USER> (butlast '(1 2 3 4 5) 2)
(1 2 3)
CL-USER> (nbutlast (list 6 7 8 9 10) 2)
(6 7 8)

      

The fact that you named your function my-butlast suggests that you may be aware of this function, but you did not mention that you want not to use this function, so I assume it is still fair game. Lightening it up is easy:

CL-USER> (defun my-butlast (list)
           (butlast list 2))
MY-BUTLAST
CL-USER> (my-butlast (list 1 2 3 4))
(1 2)

      

+3


source







All Articles